WPF + MVVM - Как связать свойство с контекстом данных родительского представления - PullRequest
4 голосов
/ 03 июля 2010

Работая с шаблоном MVVM, у меня есть пара классов моделей представлений, которые представляют двухуровневую иерархию данных, каждый с соответствующим UserControl, который представляет ее представление.Оба класса модели представления реализуют INotifyPropertyChanged, а модель представления корневого уровня предоставляет свойство, которое относится как к его собственному представлению, так и к дочернему представлению.

Представление корневого уровня получает модель представления корневого уровня в качестве контекста данных.и явно назначает контекст данных для его содержимого.Однако также необходимо привязать одно из свойств дочернего представления к вышеупомянутому общему свойству.Вот как я пытался добиться этого, но он не работает:

<UserControl x:Name="rootView">
    <StackPanel>

        <!-- other controls here -->

        <my:ChildView
            DataContext="{Binding Path=SelectedChild}"
            EditingMode="{Binding ElementName=rootView, Path=DataContext.EditingMode />
    </StackPanel>
</UserControl>

Хотя ошибок привязки во время выполнения нет, и дочернее представление правильно связывается с соответствующим экземпляром модели дочернего представления, его свойством EditingModeникогда не устанавливается.Я запустил тесты, чтобы убедиться, что соответствующее свойство модели представления изменяется и уведомляет об этом с помощью INotifyPropertyChanged, но привязка не может его обнаружить.

Есть ли лучший способ объявить эту привязкуили я сделал более простую архитектурную ошибку?

Большое спасибо за ваш совет,

Тим

Обновление: По запросу я публикую некоторыекод, показывающий очень упрощенную версию моих представлений и моделей представлений, а также результаты проведенного мной эксперимента, который может дать некоторые дополнительные подсказки.

// The relevant parts of the ParentViewModel class
public class ParentViewModel : INotifyPropertyChanged
{
    // Although not shown, the following properties
    // correctly participate in INotifyPropertyChanged

    public ChildViewModel SelectedChild { get; private set; }

    public ContentEditingMode EditingMode { get; private set; }
}

// The relevant parts of the ChildViewModel class
public class ChildViewModel : INotifyPropertyChanged
{
    // No properties of ChildViewModel affect this issue.
}

// The relevant parts of the ParentView class
public partial class ParentView : UserControl
{
    // No properties of ParentView affect this issue.
}

// The relevant members of the ChildView class
public partial class ChildView : UserControl
{
    public static readonly DependencyProperty EditingModeProperty =
        DependencyProperty.Register(
            "EditingMode",
            typeof(ContentEditingMode),
            typeof(PostView)
        );

    public ContentEditingMode EditingMode
    {
        get { return (ContentEditingMode)GetValue(EditingModeProperty); }
        set { SetValue(EditingModeProperty, value); }
    }
}

// The enumeration used for the EditingMode property
public enum ContentEditingMode
{
    Html,
    WYSYWIG
}

Мое намерение состоит в том, чтобы DataContextэкземпляру родительского представления будет назначен экземпляр ParentViewModel, и он, в свою очередь, назначит значение своего свойства SelectedChild для DataContext вложенного ChildView.Кажется, что все это работает правильно, но проблема возникает из-за того, что связь между ParentViewModel.EditingMode и ChildView.EditingMode не работает.

В попытке проверить, есть ли проблема с моим выражением привязки, я представилTextBlock, смежный с ChildView и связанный с ним так же, как свойство ParentViewModel.EditingMode:

<UserControl x:Name="rootView">
    <StackPanel>

        <!-- other controls here -->

        <TextBlock Text="{Binding ElementName=rootView, Path=DataContext.EditingMode}" />

        <my:ChildView
            DataContext="{Binding Path=SelectedChild}"
            EditingMode="{Binding ElementName=rootView, Path=DataContext.EditingMode />
    </StackPanel>
</UserControl>

В этом тесте TextBlock корректно обновляется каждый раз, когда изменяется свойство источника.Однако, если я установлю точку останова на установщик ChildView.EditingMode, он никогда не получит удар.

Я сбит с толку!

Ответы [ 2 ]

2 голосов
/ 03 июля 2010

Самый простой способ исправить это - это модель вашего вида.Реализуйте свойство EditingMode в дочерней модели представления и привяжите к нему.Таким образом, вам не нужно делать какие-либо предположения о том, каким может быть правильный способ установления привязки;кроме того, это то, что вы можете протестировать вне пользовательского интерфейса.

Редактировать

На самом деле правильное решение не так просто, но стоит знать, как это сделать.

Требуется, чтобы EditingMode в дочернем элементе управления эффективно наследовал его значение от родительского элемента управления.Похоже ли это на то, что делает что-то еще в WPF?Как и почти каждый элемент каркаса, который реализует свойства зависимости?

Реализуйте EditingMode как свойство зависимости как в родительском, так и в дочернем UserControl s и используйте наследование значения свойства, как описано здесь ,Это полностью исключает поведение наследования из модели представления и помещает его туда, где оно принадлежит.

2 голосов
/ 03 июля 2010

Посмотрите, можете ли вы просто использовать полный путь, чтобы получить режим редактирования выбранного потомка:

<my:childView
        DataContext="{Binding SelectedChild}"
        EditingMode="{Binding SelectedChild.EditingMode />
...