WPF:使用接口作为DataContext而不是实现INotifyPropertyChanged的对象

时间:2019-03-26 18:00:14

标签: c# wpf inotifypropertychanged

我已经重构了我的WPF应用程序,以便DataContexts不再是某个实现INotifyPropertyChanged的类的实例,而是我的一些自定义接口。实现每个自定义接口的对象也必须实现INotifyPropertyChanged。但是我不能再在构建时强制执行此要求。我不确定这是否是个好主意。

例如,考虑以下简单的类层次结构

// Base view model class has stock implementation of INotifyPropertyChanged.

public BaseViewModel : INotifyPropertyChanged
{
   // Assume INotifyPropertyChanged implementation with this utility to raise the event

   void RaisePropertyChanged(string property) { // ...blah blah blah ... }
}

// Interface for nameable object

public interface INameable
{
    string Name { get; set; }
}

// View model for nameable object

public class NameableViewModel : BaseViewModel, INameable
{
    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            if (value == _name) return;
            _name = value
            RaisePropertyChanged();
    }
}

// Main view model exposes named object by interface, NOT by view-model

public class MainViewModel : BaseViewModel
{
    public INameable NameableObject { get; set; } 
}

以下是绑定到INameable而不是NameableViewModel的视图

<UserControl x:Class="MyView" 
             (... blah blah blah... namespace declarations...)
             d:DataContext="{d:DesignInstance MainViewModel}">

    <TextBox DataContext={Binding NameableObject.Name, Mode=TwoWay}"/>
</UserControl>

这在WPF中很好用,因为它查询INotifyPropertyChanged的任何数据上下文。即使收到的只是INameable,它也会收到PropertyChanged通知。但是,如果我忘记正确设置类,则WPF只会默默地永远不会收到属性更改通知。我可能最终会花一些时间注意到或跟踪错误(此处的测试资源有限)。

此外,在我的后台代码中,有时我使用Josh Smith出色的INotifyPropertyChanged通过PropertyObserver手动监视某些对象。

public class PropertyObserver<TPropertySource> 
    : IWeakEventListener
    where TPropertySource : INotifyPropertyChanged
{
   ... blah blah blah..
}

确实 在构建时需要INotifyPropertyChanged,这在我使用BaseViewModel实例时非常有用。但是现在我只有一个接口,我必须自己查询它,并依靠运行时错误让我知道自己搞砸了。

这使我想到了我的问题。一位将军和一位非常具体的人:

  1. 这种设计合理吗?这是WPF工作人员在实践中通常完成的吗?还是总能确保我用作数据上下文的任何类型都已经声明实现INotifyPropertyChanged总是更好? (我意识到我可能像一个C ++程序员那样思考这个问题)
  2. 假设在我的代码中,我强制转换了一个对象,但该对象不支持我需要的接口,并且我想抛出异常。我应该抛出什么特定的.NET异常?最合适的是什么? NotSupportedException?还有吗?

1 个答案:

答案 0 :(得分:1)

我不确定您指的是什么“设计”或“实践”。我没有看到一般的模式,只是看到了接口的特定用途,对此我的目的尚不清楚。

以我的经验,最好使视图模型尽可能简单。在某些情况下,他们甚至不需要实现INotifyPropertyChanged(以只读视图模型为例)。通常,我使用提供ViewModelBase的MVVM框架(例如MVVM Light Toolkit)。我制作的几乎所有视图模型都源自ViewModelBase,并且该视图模型仅包含setter,getter和command。

对于第二个问题,我认为具体的例外情况取决于使用接口的意图。但也许是一个普遍的例外情况,可能是InvalidOperationException