刷新WPF命令

Jos*_*h G 69 wpf updating mvvm

有谁知道我怎么可以强制CanExecute调用自定义命令(约什史密斯RelayCommand)?

通常,CanExecute只要在UI上发生交互,就会调用它.如果我点击某些内容,我的命令会更新.

我有一种情况,CanExecute即幕后的计时器打开/关闭条件.因为这不是由用户交互驱动的,CanExecute所以在用户与UI交互之前不会调用.最终结果是我的Button保持启用/禁用,直到用户点击它.点击后,它会正确更新.有时Button显示已启用,但是当用户单击它时,更改为禁用而不是触发.

当计时器更改影响的属性时,如何强制更新代码CanExecute?我对影响的属性尝试了kick PropertyChanged(INotifyPropertyChanged)CanExecute,但这没有帮助.

示例XAML:

<Button Content="Button" Command="{Binding Cmd}"/>
Run Code Online (Sandbox Code Playgroud)

后面的示例代码:

private ICommand m_cmd;
public ICommand Cmd
{
    if (m_cmd == null)
        m_cmd = new RelayCommand(
            (param) => Process(),
            (param) => EnableButton);

    return m_cmd;
}

// Gets updated from a timer (not direct user interaction)
public bool EnableButton { get; set; }
Run Code Online (Sandbox Code Playgroud)

Ken*_*art 101

CommandManager.InvalidateRequerySuggested()

  • 有趣......它可以工作,但必须在UI线程上调用它.我不惊讶. (24认同)
  • 我使用了MVVM-Light messenger并创建了一个简单的RefreshCommandStatus消息,我的ViewModel现在可以发送该消息.主窗口侦听此消息并调用CommandManager.InvalidateRequerySuggest() (3认同)
  • 必须在UI线程上运行,所以不妨这样做:`UI.Dispatcher.Invoke(()=> {CommandManager.InvalidateRequerySuggested();});` (3认同)
  • 不一定,因为这可能会让你的课难以测试.试试吧,必要时将其移入服务中.另一种选择是向RelayCommand添加一个方法,允许你为该命令引发CanExecuteChanged(CommandManager.InvalidRequerySuggested使所有命令无效,这有点过分). (2认同)

Sil*_*own 28

很久以前我就知道了CommandManager.InvalidateRequerySuggested()并且使用过它,但它有时对我不起作用.我终于弄清楚为什么会这样!即使它不像其他一些动作那样抛出,你也必须在主线程上调用它.

在后台线程上调用它似乎可以工作,但有时会禁用UI.我真的希望这可以帮助别人,并节省他浪费的时间.


小智 17

解决方法是绑定IsEnabled到属性:

<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>
Run Code Online (Sandbox Code Playgroud)

然后在ViewModel中实现此属性.这也使得UnitTesting更容易使用属性而不是命令来查看命令是否可以在某个时间点执行.

我个人觉得它更方便.


R.T*_*tov 6

这个变种可能适合你:

 public interface IRelayCommand : ICommand
{
    void UpdateCanExecuteState();
}
Run Code Online (Sandbox Code Playgroud)

执行:

 public class RelayCommand : IRelayCommand
{
    public event EventHandler CanExecuteChanged;


    readonly Predicate<Object> _canExecute = null;
    readonly Action<Object> _executeAction = null;

   public RelayCommand( Action<object> executeAction,Predicate<Object> canExecute = null)
    {
        _canExecute = canExecute;
        _executeAction = executeAction;
    }


    public bool CanExecute(object parameter)
    {
       if (_canExecute != null)
            return _canExecute(parameter);
        return true;
    }

    public void UpdateCanExecuteState()
    {
        if (CanExecuteChanged != null)
            CanExecuteChanged(this, new EventArgs());
    }



    public void Execute(object parameter)
    {
        if (_executeAction != null)
            _executeAction(parameter);
        UpdateCanExecuteState();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用简单:

public IRelayCommand EditCommand { get; protected set; }
...
EditCommand = new RelayCommand(EditCommandExecuted, CanEditCommandExecuted);

 protected override bool CanEditCommandExecuted(object obj)
    {
        return SelectedItem != null ;
    }

    protected override void EditCommandExecuted(object obj)
    {
        // Do something
    }

   ...

    public TEntity SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;

            //Refresh can execute
            EditCommand.UpdateCanExecuteState();

            RaisePropertyChanged(() => SelectedItem);
        }
    }
Run Code Online (Sandbox Code Playgroud)

XAML:

<Button Content="Edit" Command="{Binding EditCommand}"/>
Run Code Online (Sandbox Code Playgroud)