更改字段时,MVVM对象fire属性更改了事件

时间:2014-08-02 02:19:02

标签: c# wpf mvvm data-binding

所以我有一个对象的MVVM绑定设置。该对象属于如下类:

public class SomeClass
{
  public int Field1 {get; set:}
  public List<MyClass> CollectionOfObjects {get; set;}
  public string Description {get; set;}
}

我的MVVM类实现了INotifyPropertyChanged ...

private SomeClass _viewableObject;
public SomeClass ViewableObject
{
    get
     {
       return _viewableObject;
     }
    set
     {
        _viewableObject = value;
        OnPropertyChanged("ViewableObject");
     }


} 

这在我定义新对象的情况下非常有用。例如:

 ViewableObject = new SomeClass();

但是我将UI组件绑定到SomeClass的字段。 Field1Description被推送到文本框,并说CollectionOfObjects被推送到DataGrid

<Datagrid .... ItemsSource = "{Binding ViewableObject.CollectionOfObjects}" ></DataGrid>

因此,如果我仅更新ViewableObject.CollectionOfObjects而不是整个ViewableObject,我如何才能更新UI以反映修改?有没有更简洁的方法来做到这一点,而不是拆分MVVM中SomeClass的每个字段?

3 个答案:

答案 0 :(得分:2)

您可以创建自己的实现INotifyCollectionChanged的集合,但是您会发现使用ObservableCollection更容易实现这一点。

答案 1 :(得分:1)

你有几个选择。最简单的方法是将CollectionOfObjectsList<MyClass>转换为ObservableCollection<MyClass> - 正如已经提到的那样。

但请注意,这只会在新项目添加到ObservableCollection时提供UI通知,或者删除现有项目。

如果您更改CollectionOfObjects指向的整个引用,则使用ObservableCollection是没有用的。相反,您需要在INotifyPropertyChanged上实施SomeClass并在设置每个属性值时引发PropertyChanged个事件。

生成的SomeClass将如下所示:

public class SomeClass : INotifyPropertyChanged
{

    public SomeClass()
    {
        CollectionOfObjects = new ObservableCollection<MyClass>();
    }

    public int Field1 
    {
        get 
        {
            return _field1;
        }
        set
        {
            if(_field1 != value)
            {

                _field1 = value;
                PropertyChanged(new PropertyChangedEventArgs("Field1"));
            }
        }
    }

    public ObservableCollection<MyClass> CollectionOfObjects 
    {
        get 
        {
            return _collectionOfObjects;
        }
        set
        {
            if(_collectionOfObjects != value)
            {

                _collectionOfObjects = value;
                PropertyChanged(new PropertyChangedEventArgs("CollectionOfObjects"));
            }
        }
    }

    public string Description
    {
        get 
        {
            return _description;
        }
        set
        {
            if(_description != value)
            {

                _description = value;
                PropertyChanged(new PropertyChangedEventArgs("Description"));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate {}

    private int _field1;
    private ObservableCollection<MyClass> _collectionOfObjects;
    private string _description;
}

请注意,严格来说,这不再是Model对象。它对INotifyPropertyChangedObservableCollection的依赖使其成为ViewModel。但是,你已经拥有其中一个......

选择是否能够容忍污染&#39;你的模型类,它成为一个ViewModel。对于某些情况,这绝对没问题。在其他情况下,优先严格区分Model和ViewModel的关注点。此时,您需要引入一个能够从Model转换为ViewModel的映射器 - 反之亦然。也许模型是数据库记录,或完全不同的东西。它可能需要依赖于其他库,从某些特定于层的基类继承,或者包含许多域逻辑。

严格分离Model和ViewModel的另一个好处是两者可以独立变化。模型可能包含UI(因此ViewModel)不需要包含的一些属性。或者,ViewModel可能会将某些属性聚合为平均值或总数等.ViewModel通常应具有映射到用户界面的属性,而Models可能不会。

最后一点说明。通过引入映射器并正确分离Model和ViewModel,您可以将现有的ViewModel类称为什么?我倾向于将其称为控制器。然后,该模式变为M-V-C-VM:Model-View-Controller-ViewModel。 Controller仍然是UI元素的DataContext,但是公开了ViewModel属性。 Controller应首先加载Model数据(可能通过存储库接口),然后让mapper将Model转换为MVVM特定的ViewModel。

如果您正在使用依赖注入,那么控制器会接受服务接口作为构造函数参数,但ViewModel不会将服务作为构造函数参数:它们将是相当愚蠢的数据包。

我重申这可能是矫枉过正,但它有时也是最好的选择。

答案 2 :(得分:0)

谢谢大家的建议。我使用的解决方案如下:

public class SomeClass : ObservableCollection<Elements>
{
  private int _field1;

  public int Field1 
   {
    get
     {
      return _field1;
     }
    set
     {
      _field1 = value;
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
     }
   }

  private string _description;
  public string Description 
   {
    get
     {
      return _description;
     }
    set
     {
      _description= value;
      OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
     }
   }

  // remove this since the class is now the collection.
  // public List<MyClass> CollectionOfObjects {get; set;}
}

现在SomeClass扩展ObservableCollection因此有一个CollectionChangedEvent

所以在我的MVVM课程中,我添加了以下内容:

处理程序

    private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        this.OnPropertyChanged("ViewableObject");

    }

将处理程序分配给事件

private SomeClass _viewableObject;
public SomeClass ViewableObject
{
     get
     {
      return _viewableObject;
     }
     set
     {
      _viewableObject = value;

      if(value != null)
         _viewableObject.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged)

      OnPropertyChanged("ViewableObject");
     }


} 

考虑到开始时的整个问题是,MVVM中的代码发出的唯一时间是新的赋值发生时,事件处理程序仅在需要时被调用。我认为这是一种接近它的简单方法。