【问题标题】:WPF disable command for a while it runningWPF 在运行时禁用命令
【发布时间】:2016-06-07 14:24:44
【问题描述】:

我需要在它运行时禁用按钮。我有这个代码:

RelayCommand.cs这是我的命令类。

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

    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

MainWindowViewModel.cs这是我的绑定命令。

private RelayCommand _getTextCommand;
public ICommand GetTextCommand
{
    get
    {
        if (_getTextCommand == null)
        {
            _getTextCommand = new RelayCommand(
                param => this.GetText(param),
                param => true
                );
        }

        return _getTextCommand;
    }
}

MainWindow.xaml 这是我绑定命令的 XAML 代码。

<Button x:Name="getTextButton" Command="{Binding GetTextCommand}" CommandParameter="{Binding ElementName=textTypeSelector, Path=SelectedIndex}"/>

这是我在命令中启动的代码:

public async void GetText(object o)
{
    await Task.Factory.StartNew(() =>
    {
        // code
    });
}

【问题讨论】:

    标签: c# wpf xaml async-await


    【解决方案1】:

    试试这个:在视图模型中添加一个布尔属性并在视图模型中实现INotifyPropertyChanged

        private bool isEnable = true;
    
        public bool IsEnable 
        {
            get { return isEnable; }
            set
            {
                isEnable = value; 
                NotifyPropertyChanged();
            } 
        }
    
        public async void GetText(object o)
        {
            await Task.Factory.StartNew(() =>
            {
    
                IsEnable = false;
            });
            IsEnable = true;
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    将其绑定到按钮的 IsEnable 属性

    <Button x:Name="abc"
                    Command="{Binding GetTextCommand}"
                    IsEnabled="{Binding IsEnable}" />
    

    根据需要设置 IsEnable。

    【讨论】:

      【解决方案2】:

      在您的 ViewModel 中添加一个布尔值以指示该命令正在执行,并在您的 GetText() 方法中设置该布尔值。

      private bool _isRunning = false;
      
      public async void GetText(object o)
      {
          await Task.Factory.StartNew(() =>
          {
              _isRunning = true;
              CommandManager.InvalidateRequerySuggested(); 
              // code
              _isRunning = false;
              CommandManager.InvalidateRequerySuggested();
          });
      }
      
      public bool CanGetText(object o){
        return ! _isRunning;
      }
      

      然后将您的 RelayCommand 更改为以下内容

      _getTextCommand = new RelayCommand(this.GetText,CanGetText);
      

      【讨论】:

      • 很好,但有 1 个问题。代码完成后,按钮不会设置为启用状态。单击它后它设置为启用状态。如何解决?
      • @user2932802 好的,我认为您需要在 ViewModel 中使用 CanExecute 方法。我会更新代码。通常应该 CommandManager.InvalidateRequerySuggested() 检查并启用按钮状态
      • 你可以用new RelayCommand(this.GetText, CanGetText);缩短它
      • 更新。如果我最小化窗口或点击它的随机位置,按钮将被启用
      【解决方案3】:

      问题是您为 CanExecute 委托传递了 true。向它传递一个在每次需要评估时都会执行的方法,并且在该方法中您可以测试该命令是否应该是可执行的。

      【讨论】:

      【解决方案4】:

      这是我正在使用的一个实现。它不需要 ViewModel 中的其他属性。

      public sealed class AsyncDelegateCommand : ICommand
      {
         private readonly Func<bool> _canExecute;
         private readonly Func<Task> _executeAsync;
         private Task _currentExecution;
      
         public AsyncDelegateCommand(Func<Task> executeAsync)
            : this(executeAsync, null)
         {
         }
      
         public AsyncDelegateCommand(Func<Task> executeAsync, Func<bool> canExecute)
         {
            if (executeAsync == null) throw new ArgumentNullException("executeAsync");
            _executeAsync = executeAsync;
            _canExecute = canExecute;
         }
      
         public event EventHandler CanExecuteChanged
         {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
         }
      
         public bool CanExecute(object parameter)
         {
            if (_currentExecution != null && !_currentExecution.IsCompleted)
            {
               return false;
            }
      
            return _canExecute == null || _canExecute();
         }
      
         public async void Execute(object parameter)
         {
            try
            {
               _currentExecution = _executeAsync();
               await _currentExecution;
            }
            finally
            {
               _currentExecution = null;
               CommandManager.InvalidateRequerySuggested();
            }
         }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        • 2022-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-15
        相关资源
        最近更新 更多