首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ObservableCollection

ObservableCollection
EN

Stack Overflow用户
提问于 2010-09-17 08:40:34
回答 4查看 1K关注 0票数 2

我有一个绑定到ObservableCollection<MyEntity>类型列表的WPF对话框。在对话框中,我希望只有在对ObservableCollection<MyEntity>列表进行更改时才启用"OK“按钮-包括在列表中添加/删除项目以及修改列表中的单个项目。

添加/删除列表中的项很简单--我为CollectionChanged事件实现了一个处理程序。

我不知道怎么做是当一个单独的项目被修改的时候。比方说,MyEntity.Name=“新值”,MyEntity类需要实现什么接口才能使它“可观察”?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-09-17 11:16:52

我喜欢slugster提供的答案,这里是基于slugster的答案的另一种构建。

如果使用DelegateCommnd绑定到OK按钮,则可以为CollectionChanged和PropertyChanged添加事件处理程序,以更改一个简单的布尔标志来控制OK按钮的状态。

代码语言:javascript
复制
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属性会触发事件...

代码语言:javascript
复制
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));
     }
  }
}
票数 0
EN

Stack Overflow用户

发布于 2010-09-17 09:45:59

MyEntity需要实现INotifyPropertyChanged,然后在发生属性更改时触发PropertyChanged事件。如下所示:

代码语言:javascript
复制
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接口的用法),并在该命令的CanExecute方法中检查ObservableCollection中的任何对象是否已设置为脏。这个检查可以用一条简单的LINQ语句来完成:myCollection.Any(x => x.IsDirty == true)
  • this方法更笨拙,更难闻……让外部对象侦听更改(通过订阅每个对象上的PropertyChanged事件),然后该外部侦听器可以启用OK按钮(通过数据绑定或直接设置)。
票数 9
EN

Stack Overflow用户

发布于 2010-09-17 16:56:18

您应该实现INotifyPropertyChanged。您可以通过以下方式完成(如您所见,此实现是完全线程安全的)。

代码语言:javascript
复制
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)第一种方式

代码语言:javascript
复制
public int MyProperty
{
     get { return _myProperty; }
     set
        {
           if (value != __myProperty)
           {
               _subVersion = value;
               OnPropertyChanged(MyPropertyPropertyName);
            }
        }
} private int _myProperty; const string MyPropertyPropertyName = "MyProperty";

2)和第二种方式

代码语言:javascript
复制
public int MyProperty
{
     get { return _myProperty; }
     set
        {
           if (value != _myProperty)
           {
               _subVersion = value;
               OnPropertyChanged(() => MyProperty);
            }
        }
} private int _myProperty; 
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3731941

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档