【问题标题】:WPF MVVM Light: Command.RaiseCanExecuteChanged() doesn't workWPF MVVM Light:Command.RaiseCanExecuteChanged() 不起作用
【发布时间】:2013-08-22 15:46:49
【问题描述】:

我的 ViewModel 中有这样的东西:

public enum WorkState
{
    Idle, Working, Stopping
};

public class MainViewModel : ViewModelBase
{
    public const string StatePropertyName = "State";
    private WorkState _state = WorkState.Idle;
    public WorkState State
    {
        get
        { return _state; }
        set
        {
            if (_state == value)
            {
                return;
            }

            RaisePropertyChanging(StatePropertyName);
            _state = value;
            RaisePropertyChanged(StatePropertyName);

            StartStopCommand.RaiseCanExecuteChanged(); // <—————————————
        }
    }


    private RelayCommand _startStopCommand;
    public RelayCommand StartStopCommand
    {
        get
        {
            return _startStopCommand
                   ?? (_startStopCommand = new RelayCommand(
                                  () =>
                                  {
                                      if (State == WorkState.Idle)
                                      {
                                          State = WorkState.Working;
                                      }
                                      else if (State == WorkState.Working)
                                      {
                                          State = WorkState.Stopping;

                                          new Thread(() =>
                                               {
                                                   Thread.Sleep(5000);
                                                   State = WorkState.Idle;
                                                }).Start();
                                      }
                                  },
                                  () => (State == WorkState.Idle ||
                                           (State == WorkState.Working)));
        }
    }
}

我的视图中的按钮:

        <Button Command="{Binding StartStopCommand}">
        <Button.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding State}" Value="{x:Static vm:WorkState.Idle}">
                        <Setter Property="Button.Content" Value="Start"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding State}" Value="{x:Static vm:WorkState.Working}">
                        <Setter Property="Button.Content" Value="Stop"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding State}" Value="{x:Static vm:WorkState.Stopping}">
                        <Setter Property="Button.Content" Value="Stop"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>

但是当我按下停止按钮并且状态属性更改为空闲时,按钮仅将其文本更改为“开始”但在我单击窗口中的某个位置之前保持禁用状态。

我将 RaiseCanExecuteChanged 添加到 State 属性的设置器中,但没有帮助。

我做错了什么?

此外,我不确定这种在同一命令中使用 Start/Stop 和 DataTriggers 设置按钮文本的方法是最好的,所以如果有人分享更好的方法,我将不胜感激。

【问题讨论】:

    标签: c# wpf mvvm mvvm-light


    【解决方案1】:

    您的问题不是 RaiseCanExecuteChanged() 不起作用,而是当您的 UI 依赖于它时,从后台线程修改您的 State 属性。

    如果我相应地修改了您的代码:(这是.Net 4.5)

    public RelayCommand StartStopCommand { get; set; }
    
    ...
    
    public MainViewModel() {
      StartStopCommand = new RelayCommand(async () => {
        switch (State) {
          case WorkState.Idle:
            State = WorkState.Working;
            break;
          case WorkState.Working:
            State = WorkState.Stopping;
            await Task.Delay(5000);
            State = WorkState.Idle;
            break;
        }
      }, () => State == WorkState.Idle || State == WorkState.Working);
    }
    

    现在您可以看到Button 从禁用切换回正确启用。

    您可以从以下地址获取样本:Here

    如果您想坚持使用您的Thread,请将其切换为:

    new Thread(
      () => {
        Thread.Sleep(5000);
        Application.Current.Dispatcher.BeginInvoke(
          new Action(() => State = WorkState.Idle));
      }).Start();
    

    ^^ 现在可以再次正常工作,因为您没有从另一个线程修改属性。

    【讨论】:

      【解决方案2】:

      【讨论】:

      • 我在 .RaiseCanExecuteChanged 之前尝试过,但也没有用。我记得 MVVM Light Commands 从某些版本开始就不再使用 CommandManager。
      • 那我不知道,抱歉...我不确定 commandmanager 与 MVVM Light 有什么关系,因为 WPF 系统会重新评估命令
      【解决方案3】:

      我认为您必须通过Dispatcher 设置您的State change

      请参阅此处了解如何执行此操作:

      http://msdn.microsoft.com/en-US/magazine/cc163328.aspx#S3 -->(图 4 更新 UI)

      【讨论】:

        猜你喜欢
        • 2011-02-21
        • 2017-08-02
        • 1970-01-01
        • 2010-10-14
        • 1970-01-01
        • 1970-01-01
        • 2020-05-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多