我的wpf窗口中有一些自定义的可编辑列表框。 我还有一个带有Property Changed的viewmodel类,看起来像这样:
public bool HasChanges
{
get
{
return customers.Any(customer => customer.Changed);
}
}
所以,我想将我的保存按钮绑定到此属性:
<Button IsEnabled="{Binding HasChanges, Mode=OneWay}"...
我的问题是如果其中一个列表框行被更改,如何更新“保存”按钮?
答案 0 :(得分:2)
为了让WPF对属性的更改做出反应,该类必须实现INotifyPropertyChanged
接口。您需要在每次更改客户时发送通知,如下所示:
class CustomerList : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private List<Customer> customers = ...
public bool HasChanges {
get {
return customers.Any(customer => customer.Changed);
}
}
// Callers who change customers inside your list must call this method
public void ChangeCustomer(Customer c) {
// Do whatever you need to do, ...
...
// then send out the notification to WPF
OnPropertyChanged("HasChanges");
}
protected void OnPropertyChanged(string name) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(name));
}
}
}
答案 1 :(得分:2)
处理按钮的正确方法是实现ICommand接口。以下是我的解决方案中的一个示例:
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
#endregion
}
然后您可以像这样数据绑定到按钮:
<Button Command="{Binding MyCommand}" .../>
剩下的就是在您的viewmodel上声明ICommand
属性:
public ICommand MyCommand { get; private set; }
//in constructor:
MyCommand = new RelayCommand(_ => SomeActionOnButtonClick(), _ => HasChanges);
然后,按钮的状态将在大多数更改时自动更新。如果由于某种原因没有 - 您可以通过调用CommandManager.InvalidateRequerySuggested
答案 2 :(得分:1)
您的ViewModel应该实现INotifyPropertyChanged
,并且当您在HasChanges
customers
举起PropertyChanged事件
更新
如果客户实施了INotifyPropertyChanged,那么客户自己就是一个可观察的集合。您可以订阅,并根据取消订阅的操作,订阅CollectionChangedEvent
个customers
集合中{{1}}的所有客户。
答案 3 :(得分:0)
如果ViewModel实现了INotifyPropertyChanged,则只需要在HasChanges上调用OnPropertyChanged()方法。使用Prism,等效方法是RaisePropertyChanged。
但是,对于MVVM,您可能希望将该测试放在命令的CanExecute方法中,该方法绑定到按钮Command属性。这将自动处理IsEnabled。
答案 4 :(得分:0)
按钮不知何故必须接收通知。在您的情况下,您可能在viewmodel中实现了INotifyPropertyChanged接口。当您的“列表框行已更改”时,您应该为“HasChanges”属性引发PropertyChanged事件。但是在viewmodel中应该注意到更改,并且应该引发事件。 作为一个不同的解决方案,因为你有一个viewmodel你可以在你的按钮上使用一个命令,CanExecute会让逻辑返回true或false,当你发生更改时也必须用它来标记。