简体   繁体   English

用于启用/禁用按钮的RelayCommand与预期的不同

[英]The RelayCommand for enable/disable a button don't work like expected

The case is that I try to disable a button in the window form when it was clicked and after some time (some seconds) it should be enabled again. 这种情况是,我尝试在单击窗口表单中的按钮时将其禁用,并且在一段时间(几秒钟)后应再次启用它。

But this didn't work. 但这没有用。 After a click on the button the command set the enabled to false and after some seconds the command set it back to true (I tested it, the order is right and it set it to true again) but the button is still not enabled on the window form. 单击按钮后,该命令将启用设置为false ,几秒钟后,该命令将其设置为true (我测试了该命令,顺序是正确的,并且再次将其设置为true ),但是该按钮仍未启用窗口形式。

For that case I use a RelayCommmand . 对于这种情况,我使用RelayCommmand The RelayCommand is a standard class you find on Internet and will be shown in the end. RelayCommand是您在Internet上找到的标准类,将在最后显示。 To organise the command I wrote a class called Testclass : 为了组织命令,我编写了一个称为Testclass的类:

class Testclass
{
    private bool _testValueCanExecute;
    public bool TestValueCanExecute
    {
        get { return _testValueCanExecute; }
        set
        {
            _testValueCanExecute = value;
            OnPropertyChanged();
        }
    }

    public ICommand TestValueCommand { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
    public Testclass()
    {
        TestValueCommand = new RelayCommand(TestMethod, param => _testValueCanExecute);
        TestValueCanExecute = true;
    }

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private async void TestMethod(object obj)
    {
        TestValueCanExecute = false;
        await Task.Delay(3000);
        TestValueCanExecute = true;
    }
}

In the XAML File I added a button as followed: 在XAML文件中,我添加了一个按钮,如下所示:

<Button x:Name="TestButton" Command="{Binding TestValueCommand}" Content="Test Button" HorizontalAlignment="Left" Margin="149,96,0,0" VerticalAlignment="Top" Width="75"/>

The MainWindow code looks as followed: MainWindow代码如下所示:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new Testclass();
    }
}

So the RelayCommand use the TestMethod method set the command enable variable to false , wait 3 seconds and set them back to true . 因此, RelayCommand使用TestMethod方法将命令enable变量设置为false ,等待3秒钟,然后将它们设置为true But as I wrote above the button on the window form still not enabled. 但是,正如我在上方所述,窗口窗体上的按钮仍未启用。

It would be nice to understand what happens here and how I can solve this. 很高兴了解这里发生的事情以及如何解决此问题。

Update: I use the following Code for the RelayCommand : 更新:我对RelayCommand使用以下代码:

public class RelayCommand : ICommand
{
    private Action<object> execute;
    private Func<object, bool> canExecute;

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

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return this.canExecute == null || this.canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        this.execute(parameter);
    }
}

The RelayCommand is a standard class you find on Internet ... RelayCommand是您在Internet上找到的标准类...

There is no such thing as a "standard class you find on Internet". 没有“在互联网上找到的标准班级”这样的东西。 In fact there are several different implementations of the RelayCommand available "on the Internet". 实际上,“在Internet上”有几种不同的RelayCommand实现。

A good implementation should contain a method for raising the CanExecuteChanged event. 一个好的实现应包含一个引发CanExecuteChanged事件的方法。 MvvmLight's implementation has a RaiseCanExecuteChanged() method that does this. MvvmLight的实现具有执行此操作的RaiseCanExecuteChanged()方法。 You need to call this one to "refresh" the status of the command: 您需要调用此命令来“刷新”命令的状态:

private async void TestMethod(object obj)
{
    RelayCommand cmd = TestValueCommand as RelayCommand;
    TestValueCanExecute = false;
    cmd.RaiseCanExecuteChanged();
    await Task.Delay(3000);
    TestValueCanExecute = true;
    cmd.RaiseCanExecuteChanged();
}

The event is not raised automatically when you set the TestValueCanExecute property and raise the PropertyChanged event for the view model. 当您设置TestValueCanExecute属性并引发视图模型的PropertyChanged事件时, 不会自动引发该事件。

Edit: Your implementation doesn't have any RaiseCanExecuteChanged() method. 编辑:您的实现没有任何RaiseCanExecuteChanged()方法。 Add one to your RelayCommand class and call it as per above: 将一个添加到您的RelayCommand类中,然后按上述方式调用它:

public void RaiseCanExecuteChanged()
{
    CommandManager.InvalidateRequerySuggested();
}

I strongly recommend using existing frameworks, instead of inveting the wheel once again. 我强烈建议您使用现有的框架,而不是再费周折。 Take a look at ReactiveUI ReactiveCommand 看看ReactiveUI ReactiveCommand

In your case, it would do all the work by itself: 在您的情况下,它将自行完成所有工作:

TestValueCommand = ReactiveCommand.CreateFromTask(async () => await Task.Delay(500));

You bind that command to a button in xaml and the button is disabled until command is done. 您将该命令绑定到xaml中的按钮,并且该按钮将被禁用,直到命令完成。

You can easily add another condition for disabling the command, and then, binding will disable button 您可以轻松地添加另一个条件来禁用该命令,然后绑定将禁用按钮

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM