【问题标题】:Is it a bad practice to define a ViewModel as a DependencyProperty for data-binding?将 ViewModel 定义为数据绑定的 DependencyProperty 是一种不好的做法吗?
【发布时间】:2017-02-04 15:55:29
【问题描述】:

我有一个 UserControl MyView,它有一个内部 UserControl SubView。

2个用户控件的视图模型与视图具有相同的层次结构, 即,MyViewModel 内部有 SubViewModel,如下面的代码所示。

public class MyViewModel
{
    private readonly SubViewModel _subViewModel = new SubViewModel();

    public SubViewModel SubViewModel { get { return _subViewModel; } }

    private void HandleSubViewModel()
    {
        // Do what is necessary to handle SubViewModel
    }
}

我的问题是关于如何将 SubViewModel 绑定到 SubView。

现在我在 SubView 的代码隐藏中定义 SubViewModel 并将其绑定到 MyViewModel 类的 SubViewModel 属性。

public partial class SubView : UserControl
{
    public static readonly DependencyProperty SubViewModelProperty = DependencyProperty.Register(
    "SubViewModel", typeof (SubViewModel), typeof (SubView), new PropertyMetadata(default(SubViewModel)));

    public SubViewModel SubViewModel
    {
        get { return (SubViewModel) GetValue(SubViewModelProperty); }
        set { SetValue(SubViewModelProperty, value); }
    }
}

<UserControl x:Class="MyProject.View.MyView"
             xmlns:parts="clr-namespace:MyProject.View.Parts">
    <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}, Path=MyViewModel}">
        <parts:SubView SubViewModel="{Binding SubViewModel}"/>
    </Grid>
</UserControl>

以这种方式绑定内部视图模型是一种不好的做法吗?

如果是这样,我怎样才能更好地绑定它?

【问题讨论】:

    标签: c# wpf mvvm data-binding viewmodel


    【解决方案1】:

    它可能不好的一个原因是,如果SubViewModel 中的属性发生更改,MyViewModel 将无法知道这一点。因此,例如如果您需要在 MyViewModel 级别执行和处理任何验证,您将无法执行此操作。

    为了解决这个问题,当属性发生变化时;您必须在SubViewModel 中引发一个事件并让MyViewModel 订阅它并在收到它后做出适当的反应。

    除此之外,我认为没有任何缺点。但请阅读这些链接以获取更多信息: MVVM and nested view models

    MVVM: How to handle interaction between nested ViewModels?

    【讨论】:

    • 非常感谢您的快速答复。
    • 非常感谢您的快速答复。在我的实际代码中,SubViewModel 实现了INotifyPropertyChanged,这样MyViewModel 就可以知道SubViewModel 属性的变化。
    • 是的,为什么不呢?在SubViewModel 中有一个类似SubViewModelChanged 的事件,并且每当您希望通知属性更改时,请引发此事件。在MyViewModel 中只需订阅此事件并采取相应的行动..
    【解决方案2】:

    你可以这样做: 查看模型:

    public class MyViewModel
    {
        private readonly SubViewModel _subViewModel;
    
        public SubViewModel SubViewModel
        {
            get { return _subViewModel; }
        }
    
        public MyViewModel()
        {
            _subViewModel = new SubViewModel();
            _subViewModel.Text1 = "blabla";
        }
    }
    
    public class SubViewModel : DependencyObject
    {
        public string Text1
        {
            get { return (string)GetValue(Text1Property); }
            set { SetValue(Text1Property, value); }
        }
    
        public static readonly DependencyProperty Text1Property =
            DependencyProperty.Register("Text1", typeof(string), typeof(SubViewModel));
    }
    

    子用户控件:

    <UserControl x:Class="WpfApplication1.SubUserControl"
             xmlns= ... >
    <Grid Height="200" Width="300" Background="Aqua">
          <TextBlock Text="{Binding SubViewModel.Text1}" /> 
    </Grid>
    

    【讨论】:

    • 感谢您的回答,但我想阻止SubViewModel 继承DependencyObject,因为DependencyObject 具有线程关联性。
    • 没问题。 SubViewModel.Text1 不需要是依赖属性。实现 INotifypropertyChanged 时可以是普通属性。
    猜你喜欢
    • 1970-01-01
    • 2019-09-13
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多