6

我的 wpf 窗口上有一些自定义的可编辑列表框。我还有一个带有 Property Changed 的​​ viewmodel 类,如下所示:

public bool HasChanges
{
    get
    {
        return customers.Any(customer => customer.Changed);
    }
}

所以,我想将我的保存按钮绑定到这个属性:

<Button IsEnabled="{Binding HasChanges, Mode=OneWay}"...

我的问题是如果更改列表框行之一,如何更新保存按钮?

4

5 回答 5

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));
        }
    }
}
于 2013-08-19T10:30:20.200 回答
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}" .../>

剩下的就是ICommand在你的视图模型上声明一个属性:

public ICommand MyCommand { get; private set; }

//in constructor:
MyCommand = new RelayCommand(_ => SomeActionOnButtonClick(), _ => HasChanges);

然后按钮的状态将根据大多数更改自动更新。如果由于某种原因没有 - 您可以通过调用强制更新CommandManager.InvalidateRequerySuggested

于 2013-08-19T10:43:30.333 回答
1

您的 ViewModel 应该实现并且应该在您更改客户时INotifyPropertyChanged引发 PropertyChanged 事件HasChangescustomers

更新:

如果客户实现 INotifyPropertyChanged 并且客户它本身就是一个可观察的集合。您可以订阅,并根据取消订阅操作,订阅CollectionChangedEventcustomers集合中的所有客户。

于 2013-08-19T10:26:46.810 回答
0

如果你的 ViewModel 实现了 INotifyPropertyChanged,你只需要在 HasChanges 上调用 OnPropertyChanged() 方法。对于 Prism,等效方法是 RaisePropertyChanged。

但是,对于 MVVM,您可能希望将该测试放在您的命令的 CanExecute 方法中,该方法绑定到您的按钮 Command 属性。这将自动处理 IsEnabled。

于 2013-08-19T10:28:47.203 回答
0

该按钮必须以某种方式接收通知。在您的情况下,您可能在视图模型中实现 INotifyPropertyChanged 接口。当您的“列表框行更改”时,您应该为“HasChanges”属性引发 PropertyChanged 事件。但是在您的视图模型中应该注意更改,并且应该引发事件。作为一个不同的解决方案,因为你有一个视图模型,你可以在你的按钮上使用一个命令,并且 CanExecute 的逻辑会返回 true 或 false,当发生更改时也必须由你标记。

于 2013-08-19T10:31:16.313 回答