使用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
的{1}}。所有这些似乎都能正常工作,但问题出现了,因为ChildView
和ParentViewModel.EditingMode
之间的绑定不起作用。
为了测试我的绑定表达式是否存在问题,我在ChildView.EditingMode
附近引入了TextBlock
,并将其绑定到ChildView
属性:
ParentViewModel.EditingMode
在此测试中,每次source属性更改时都会正确更新<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
的设置器上设置断点,它永远不会被击中。
我很困惑!
答案 0 :(得分:2)
看看你是否可以使用完整路径来获得所选孩子的编辑模式:
<my:childView
DataContext="{Binding SelectedChild}"
EditingMode="{Binding SelectedChild.EditingMode />
答案 1 :(得分:2)
解决此问题的最简单方法是在您的视图模型中。在子视图模型中实现EditingMode
属性并绑定到它。这样,您不必对建立绑定的正确方法做出任何猜测;此外,您可以在UI之外进行测试。
修改强>
实际上,正确的解决方案并不那么简单,但值得知道如何做。
您希望子控件中的EditingMode
有效地从父控件继承其值。这听起来像WPF中的其他内容吗?就像几乎所有实现依赖属性的框架元素一样?
在父{和{1}}中实现EditingMode
作为依赖属性,并使用属性值继承,如here所述。这将继承行为完全取出视图模型,并将其放在它所属的位置。