【问题标题】:Alternatives to OnPropertyChangedOnPropertyChanged 的​​替代品
【发布时间】:2013-05-10 18:13:39
【问题描述】:

我正在尝试解决在 WPF 中实现 MVVM 时遇到的问题。下面我的Contact 类是由实体框架填充的模型。

public class Contact : INotifyPropertyChanged
{
    public string _firstName;
    public string FirstName
    {
        get
        {
            return _firstName;
        }
        set
        {
            _firstName = value;
            OnPropertyChanged("FirstName");
        }
    }

    public string _lastName;
    public string LastName
    {
        get
        {
            return _lastName;
        }
        set
        {
            _lastName = value;
            OnPropertyChanged("LastName");
        }
    }

    //INotifyPropertyChanged implementation omitted for brevity
}

这是我的 ViewModel:

public class ContactViewModel
{
    public Contact MyContact { get; set; }

    public string FullName
    {
        get
        {
            return MyContact.FirstName + " " + MyContact.LastName;
        }
    }
}

所以我将 View 的数据源设置为 ContactViewModel 的实例,并将两个 TextBox 绑定到 MyContact.FirstNameMyContact.LastName。我将TextBlock 绑定到FullName。当我更改任何一个文本框时,全名TextBlock 不会更新(显然,我没有在任何地方做OnPropertyChanged("FullName"))。

问题是,我在哪里添加OnPropertyChanged("FullName")我不一定要修改我的模型,因为它正在其他地方使用,我不想将它绑定到我的 ViewModel。

我需要重新考虑我的架构吗?

【问题讨论】:

  • 通常是 ViewModel 实现了 INPC 接口,而不是模型。
  • 如果是这样,我将如何绑定到我的模型?
  • 有些人在他们的 viewModel 上复制属性。这些属性包装了模型上的属性,您的视图仅绑定到您的视图模型。两种方法都有效。
  • 准确地说,viewmodel 只包含视图需要显示或操作的属性。 VM 中的属性使用模型的属性作为其支持字段。

标签: wpf mvvm inotifypropertychanged


【解决方案1】:

我需要重新考虑我的架构吗?

这可以通过您当前的架构解决。您只需要将调用从您的 Contact 对象传播到您的 viewModel 对象。

您需要在 viewModel 中实现 INotifyPropertyChanged 来实现这一点。

有些东西这样:

public class ContactViewModel : INotifyPropertyChanged
{
    //INotifyPropertyChanged implementation omitted for brevity...

    private Contact _myContact;

    public Contact MyContact 
    { 
        get
        {
            return _myContact;
        } 
        set
        {
            _myContact.PropertyChanged -= myHandler;
            _myContact = value;
            _myContact.PropertyChanged += myHandler;
        }
    }

    public string FullName
    {
        get
        {
            return MyContact.FirstName + " " + MyContact.LastName;
        }
    }

    private void myHandler(Object sender, PropertyChangedEventArgs e)
    {
        OnPropertyChanged("FullName");
    }
}

我还建议查看 MVVM Foundation,因为其中包含一个名为 PropertyObserver 的类,旨在使此类事情的连接更加容易。

如果您想采用 Big Daddy 建议的更纯 MVVM 的方法,您需要执行以下操作:

public class ContactViewModel : INotifyPropertyChanged
{
    // INotifyPropertyChanged implementation omitted for brevity...

    // You will require some way of setting this, either via a property
    // or the viewModel constructor...
    private Contact _myContact;

    public string FirstName
    {
        get { return _myContact.FirstName; }
        set
        {
            _myContact.FirstName = value;
            OnPropertyChanged("FirstName");
            OnPropertyChanged("FullName");
        }
    }

    public string LastName
    {
        get { return _myContact.LastName; }
        set
        {
            _myContact.LastName = value;
            OnPropertyChanged("LastName");
            OnPropertyChanged("FullName");
        }
    }

    public string FullName
    {
        get
        {
            return MyContact.FirstName + " " + MyContact.LastName;
        }
    }
}

【讨论】:

  • 来自问题:我不一定要修改我的模型,因为它正在其他地方使用,我不会将它绑定到我的 ViewModel。
  • 所以这会在任何属性更改时触发 OnPropertyChanged("FullName"),而不仅仅是 FirstName 或 LastName,对吗?
  • @MikeCole 是的,但是如果您想通过在属性更改处理程序中添加if (e.PropertyName == "FirstName" || e.PropertyName == "LastName") 检查来轻松避免这种情况。 (另外,在尝试在 setter 中附加和分离 PropertyChanged 处理程序之前,您需要检查 _myContact 是否为 null
  • @Mike Cole - Rachel 说了什么 ^
  • @Rachel 我想这是你今天第二次帮助我了,谢谢!
【解决方案2】:
Do I need to rethink my architecture?

也许……

在我看来,您正在将视图的属性绑定到您的视图模型 (ContactViewModel) 您的模型 (Contact)。您的视图可以通过您的视图模型查看您的公共模型的属性等 - 我认为这不好。看起来违反了Law of Demeter。我宁愿看到您使用您的视图模型作为模型的包装器/外观。这肯定会创造更多的工作,但我认为它为您提供了更好的设计和更大的灵活性。您的视图模型需要实现 INotifyPropertyChanged 才能使其正常工作。

【讨论】:

  • 这个问题是我的模型实现了 IDataErrorInfo 并且有验证。现在,这正在传递给我的视图并得到妥善处理。如果我映射到 ViewModel 的属性,我会丢失这些验证规则吗?
  • 我个人认为直接绑定到模型没有任何问题,尤其是在只有一个开发人员同时处理模型和视图模型层的小型应用程序中。这不是“纯粹的 MVVM”方法,但它更实用,因为它减少了工作量和代码重复。
  • @Rachel...如果是针对小型应用程序,您有道理,但我的经验表明,如果不是,则不然
  • @MikeCole...如果需要,您仍然可以在模型中保留验证规则。您只需在 VM 的属性中调用 YourPrivateModel.RaisePropertyChanged()。如果您愿意,我可以发布更多代码。
  • 是的,但是视图不需要绑定到实现 IDataErrorInfo 的实体来获得自动验证吗?如果我将绑定更改为使用 ViewModel,如何重用模型中的规则?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2012-01-25
  • 2015-08-05
  • 2011-01-01
  • 2011-10-24
  • 2011-05-31
相关资源
最近更新 更多