我有一个绑定到ObservableCollection<MyEntity>类型列表的WPF对话框。在对话框中,我希望只有在对ObservableCollection<MyEntity>列表进行更改时才启用"OK“按钮-包括在列表中添加/删除项目以及修改列表中的单个项目。
添加/删除列表中的项很简单--我为CollectionChanged事件实现了一个处理程序。
我不知道怎么做是当一个单独的项目被修改的时候。比方说,MyEntity.Name=“新值”,MyEntity类需要实现什么接口才能使它“可观察”?
发布于 2010-09-17 11:16:52
我喜欢slugster提供的答案,这里是基于slugster的答案的另一种构建。
如果使用DelegateCommnd绑定到OK按钮,则可以为CollectionChanged和PropertyChanged添加事件处理程序,以更改一个简单的布尔标志来控制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));
}
}
}发布于 2010-09-17 09:45:59
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;
}解决此问题的两种方法是:
OK按钮绑定到一个命令(查看ICommand接口的用法),并在该命令的CanExecute方法中检查ObservableCollection中的任何对象是否已设置为脏。这个检查可以用一条简单的LINQ语句来完成:myCollection.Any(x => x.IsDirty == true)发布于 2010-09-17 16:56:18
您应该实现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; https://stackoverflow.com/questions/3731941
复制相似问题