代码之家  ›  专栏  ›  技术社区  ›  Josh G

刷新wpf命令

  •  68
  • Josh G  · 技术社区  · 16 年前

    有人知道我怎么能强迫吗 CanExecute 接到定制命令的电话(乔希·史密斯的 RelayCommand )?

    通常情况下, 可执行的 在用户界面上发生交互时调用。如果我点击某个东西,我的命令就会更新。

    我的情况是 可执行的 正在由后台计时器打开/关闭。因为这不是由用户交互驱动的, 可执行的 直到用户与UI交互后才调用。最终结果是 Button 在用户单击之前保持启用/禁用状态。单击后,它将正确更新。有时 纽扣 显示为已启用,但当用户单击时,它将更改为已禁用而不是激发。

    当计时器更改影响的属性时,如何在代码中强制更新 可执行的 ?我试着开火 PropertyChanged ( INotifyPropertyChanged )影响的财产 可执行的 但是那没有帮助。

    实例XAML:

    <Button Content="Button" Command="{Binding Cmd}"/>
    

    示例代码隐藏:

    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; }
    
    6 回复  |  直到 6 年前
        2
  •  28
  •   SilverSideDown    12 年前

    很久以前我就知道commandManager.invalidRequerySuggested(),并使用过它,但有时它对我不起作用。我终于明白为什么会这样!尽管它不像其他动作那样抛出,但您必须在主线程上调用它。

    在后台线程上调用它似乎可以工作,但有时会使UI处于禁用状态。我真的希望这能帮助一些人,节省我浪费的时间。

        3
  •  16
  •   Martin Liversage    7 年前

    解决这一问题的方法是有约束力的 IsEnabled 财产:

    <Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>
    

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

    我个人觉得这样更方便。

        4
  •  6
  •   KyleMit Steven Vachon    11 年前

    可能这个变种适合你:

     public interface IRelayCommand : ICommand
    {
        void UpdateCanExecuteState();
    }
    

    实施:

     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();
        }
    }
    

    使用简单:

    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);
            }
        }
    

    XAML:

    <Button Content="Edit" Command="{Binding EditCommand}"/>
    
        5
  •  4
  •   KyleMit Steven Vachon    11 年前

    谢谢大家的提醒。下面是一些关于如何将该调用从bg线程封送到ui线程的代码:

    private SynchronizationContext syncCtx; // member variable
    

    在构造函数中:

    syncCtx = SynchronizationContext.Current;
    

    在后台线程上,要触发请求:

    syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );
    

    希望有帮助。

    ——米迦勒

        6
  •  0
  •   Coden bkaid    6 年前

    要仅更新单个galasoft.mvmlight.commandwpf.relaycommand,可以使用

    mycommand.RaiseCanExecuteChanged();
    

    对于我来说,我已经创建了一个扩展方法:

    public static class ExtensionMethods
        {
            public static void RaiseCanExecuteChangedDispatched(this RelayCommand cmd)
            {
                System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
            }
    
            public static void RaiseCanExecuteChangedDispatched<T>(this RelayCommand<T> cmd)
            {
                System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
            }
        }