2010-09-17 42 views
2

我有一個綁定到ObservableCollection<MyEntity>類型列表的WPF對話框。在對話框中,我想只有當更改了ObservableCollection<MyEntity>列表所做啓用「確定」按鈕 - 這包括添加/從列表中刪除項目和修改列表中的個別項目。的ObservableCollection

對於添加/從列表中刪除的項目,很容易 - 我實現了一個處理程序CollectionChanged事件。

我不知道該怎麼辦的時候是一個單獨的項目被修改。說,MyEntity.Name =「新值」,MyEntity類需要實現什麼接口,使其「可觀察」?

回答

0

我喜歡slugster提供的答案,這裏是slugster的答案替代建築。

如果您使用DelegateCommnd你可以添加事件處理程序CollectionChanged和的PropertyChanged改變一個簡單的布爾標誌來控制OK按鈕的狀態綁定到你的OK按鈕。

public class MainViewModel : ViewModelBase 
{ 
    public DelegateCommand<object> RunCommand { get; set; } 
    public DelegateCommand<object> OkCommand { get; set; } 
    private bool enableOk = false; 
    private bool setOK = false; 
    private ObservableCollection<MyEntity> _entites = new ObservableCollection<MyEntity>(); 

    public MainViewModel() 
    { 
    _entites.CollectionChanged += (s, e) => 
    { 
     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      // handle property changing 
      foreach (MyEntity item in e.NewItems) 
      { 
       ((INotifyPropertyChanged)item).PropertyChanged += (s1, e1) => { if (setOK) enableOk = true; }; 
      } 
     } 
     // handle collection changing 
     if (setOK) enableOk = false; 
    }; 

    MyEntity me1 = new MyEntity { Name = "Name", Information = "Information", Details = "Detials" }; 
    MyEntity me2 = new MyEntity { Name = "Name", Information = "Information", Details = "Detials" }; 
    MyEntity me3 = new MyEntity { Name = "Name", Information = "Information", Details = "Detials" }; 
    _entites.Add(me1); 
    _entites.Add(me2); 
    _entites.Add(me3); 

    // allow collection changes now to start enabling the ok button... 
    setOK = true; 

    RunCommand = new DelegateCommand<object>(OnRunCommnad, CanRunCommand); 
    OkCommand = new DelegateCommand<object>(OnOkCommnad, CanOkCommand); 
    } 

    private void OnRunCommnad(object obj) 
    { 
    MyEntity me = new MyEntity { Name = "Name", Information = "Information", Details = "Detials" }; 

    // causes ok to become enabled 
    _entites.Add(me); 

    MyEntity first = _entites[0]; 

    // causes ok to become enabled 
    first.Name = "Zamboni"; 
    } 

    private bool CanRunCommand(object obj) 
    { 
    return true; 
    } 

    private void OnOkCommnad(object obj) 
    { 
    } 

    private bool CanOkCommand(object obj) 
    { 
    return enableOk; 
    } 
} 

這裏是一個版本myEntity所(類似於slugster提供的一個):
只有Name屬性在這個例子中觸發一個事件...

public class MyEntity : INotifyPropertyChanged 
{ 
    private string _name = string.Empty; 
    public string Name 
    { 
    get 
    { 
     return _name; 
    } 
    set 
    { 
     _name = value; 
     OnPropertyChanged("Name"); 
    } 
    } 
    public string Information { get; set; } 
    public string Details { get; set; } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string propertyName) 
    { 
    PropertyChangedEventHandler handler = PropertyChanged; 

    if (handler != null) 
    { 
     handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    } 
} 
8

MyEntity需要實現INotifyPropertyChanged,然後當發生屬性更改時觸發PropertyChanged事件。就像這樣:

public class MyEntity : INotifyPropertyChanged 
{ 
    public bool MyFlag 
    { 
     get { return _myFlag; } 
     set 
     { 
      _myFlag = value; 
      OnPropertyChanged("MyFlag"); 
     } 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

兩種方法可以解決這個有:

  • 有一個事件監聽器內部的對象,然後設置一個IsDirty標誌每當屬性發生變化。然後OK按鈕被綁定到的命令(檢查出的ICommand接口的使用),以及在你檢查是否有任何在的ObservableCollection對象的已設置爲髒命令的CanExecute方法。這個檢查可以通過一個簡單的LINQ語句來完成:myCollection.Any(x => x.IsDirty == true)

  • 這個方法更加笨拙和臭.... ....有一個外部對象監聽更改(通過訂閱每個對象上的PropertyChanged事件),並且外部聽衆可以啓用OK按鈕(通過數據綁定或直接設置)。

+0

添加到@slugster的的ObservableCollection有CollectionChanged事件,您可以設置,說什麼旗在所述事件的處理者中改變 – 2010-09-17 02:31:32

0

你應該實現INotifyPropertyChanged。您可以通過以下方式做到這一點 (你可以看到,這個實現是完全線程安全的)

private readonly object _sync = new object(); 

public event PropertyChangedEventHandler PropertyChanged 
{ 
    add { lock (_sync) _propertyChanged += value; } 
    remove { lock (_sync) _propertyChanged -= value; } 
} private PropertyChangedEventHandler _propertyChanged; 

protected void OnPropertyChanged(Expression<Func<object>> propertyExpression) 
{ 
    OnPropertyChanged(GetPropertyName(propertyExpression)); 
} 

protected string GetPropertyName(Expression<Func<object>> propertyExpression) 
{ 
    MemberExpression body; 

    if (propertyExpression.Body is UnaryExpression) 
     body = (MemberExpression) ((UnaryExpression) propertyExpression.Body).Operand; 
    else 
     body = (MemberExpression) propertyExpression.Body; 

    return body.Member.Name; 
} 

protected virtual void OnPropertyChanged(string propertyName) 
{ 
    var handler = _propertyChanged; 
    if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
} 

按照我上述的實現,可以通過兩種方式 1)通知有關更改第一種方式

public int MyProperty 
{ 
    get { return _myProperty; } 
    set 
     { 
      if (value != __myProperty) 
      { 
       _subVersion = value; 
       OnPropertyChanged(MyPropertyPropertyName); 
      } 
     } 
} private int _myProperty; const string MyPropertyPropertyName = "MyProperty"; 

2)和第二方式

public int MyProperty 
{ 
    get { return _myProperty; } 
    set 
     { 
      if (value != _myProperty) 
      { 
       _subVersion = value; 
       OnPropertyChanged(() => MyProperty); 
      } 
     } 
} private int _myProperty; 
0

另一種解決方案可能是一個自定義的觀察集合,要求項目實施INotifyPropertyChanged。用戶必須在OnItemPropertyChanged事件中附加處理程序,只要集合中某個項目的屬性發生更改,該事件就會被調用。

public class ObservableCollectionEnhanced<T> : ObservableCollection<T> where T : INotifyPropertyChanged 
{ 
    public ObservableCollectionEnhanced() 
    : base() 
    { } 

    public ObservableCollectionEnhanced(IEnumerable<T> collection) 
    : base(collection) 
    { 
    foreach (T item in Items) 
     item.PropertyChanged += OnItemPropertyChanged; 
    } 

    public ObservableCollectionEnhanced(List<T> list) 
    : base(list) 
    { 
    foreach (T item in Items) 
     item.PropertyChanged += OnItemPropertyChanged; 
    } 

    public event System.ComponentModel.PropertyChangedEventHandler ItemPropertyChanged; 
    public void OnItemPropertyChanged(Object sender, PropertyChangedEventArgs e) 
    { 
    if (null != ItemPropertyChanged) 
     ItemPropertyChanged(sender, e); 
    } 

    protected override void InsertItem(int index, T item) 
    { 
    base.InsertItem(index, item); 
    item.PropertyChanged += OnItemPropertyChanged; 
    } 

    protected override void RemoveItem(int index) 
    { 
    T item = this.Items[index]; 
    item.PropertyChanged -= OnItemPropertyChanged; 
    base.RemoveItem(index); 
    } 

    protected override void SetItem(int index, T item) 
    { 
    T oldItem = Items[index]; 
    base.SetItem(index, item); 
    oldItem.PropertyChanged -= OnItemPropertyChanged; 
    item.PropertyChanged += OnItemPropertyChanged; 
    } 
} 

配置的處理程序如下:

public void OnItemPropertyChanged(Object sender, PropertyChangedEventArgs e) 
{ 
    System.Diagnostics.Debug.WriteLine("Update called on {0}", sender); 
} 

...

collection.ItemPropertyChanged += OnItemPropertyChanged;