簡體   English   中英

CanExecute 僅部分起作用

[英]CanExecute works only partial

我正在開發一個 WPF .NET 5 應用程序,它需要使用按鈕命令處理更長的任務。 在任務完成之前,該按鈕應該被禁用。 我正在使用 Microsoft.Toolkit.Mvvm 的 RelayCommand:
BtnCmd = new RelayCommand(DoSomething, CanDoSomething);
DoSomething 方法所做的第一件事是使CanDoSomething的返回值為假。 這可以防止再次執行 DoSomething,但它在 Button 上不可見。
在研究時,我發現https://github.com/CommunityToolkit/MVVM-Samples/issues/41上確實是這種情況:

“Sergio0694 於 2021 年 3 月 28 日發表評論” :“沒錯,默認情況下,RelayCommand 不會在 WPF 上自動更新其視覺對象 state...”。

他推薦的解決方案是使用: https://gist.github.com/Sergio0694/130bc344e552e501563546454bd4e62a

<button xmlns:input="using:Microsoft.Toolkit.Mvvm.Wpf.Input"    
        Command="{Binding Command}"
        input:RelayCommandExtensions.IsCommandUpdateEnabled="True"/> 

我的 DoSomething 方法如下所示:

private async void DoSomething()
{
    PropertyCheckedByCanDoSomething = false;
    await Task.Delay(1000);
    PropertyCheckedByCanDoSomething = true;
}

它將提供所需的視覺效果,但僅在線: PropertyCheckedByCanDoSomething = false; 使用PropertyCheckedByCanDoSomething = true; 該效果僅在單擊應用程序或進行 window 切換后可見。
我怎樣才能解決這個問題?
非常感謝您的支持。

在不知道所有綁定等情況的情況下,我可能會通過子類化您的中繼命令來接近它,例如

using System;
using System.Windows.Input;
namespace MyTestApp
{
    public class MyRelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Func<object, bool> _canExecute;

        public MyRelayCommand(Action<object> execute) : this(execute, CanAlwaysExecute)
        { }

        public MyRelayCommand(Action<object> execute, Func<object, bool> canExecute)
        {
            // Lamda expression to execute each respectively
            _execute = execute;
            _canExecute = canExecute;
        }

        // The CanExecuteChanged event handler is required from the ICommand interface
        public event EventHandler CanExecuteChanged;
        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, new EventArgs());
        }

        public bool CanExecute(object cmdParm)
        { return _isMyTaskRunning && _canExecute(cmdParm); }

        public static bool CanAlwaysExecute(object cmdParm)
        { return true; }

        public void Execute(object cmdParm)
        {
            // prevent double action if running vs not
            if (_isMyTaskRunning)
                return;

            // flag it to prevent double action
            _isMyTaskRunning = true;

            // trigger raising the CanExecute changed which will update the user interface
            RaiseCanExecuteChanged();
    
            // turn off when done, but if being done from a "task()" process, 
            // you probably want to have a return function be called when the 
            // TASK is finished to re-enable the button... maybe like
            System.Threading.Tasks.Task.Run(() => _execute)
                                    .ContinueWith(task => { ButtonTaskIsComplete(); } );
        }

        private bool _isMyTaskRunning = false;
        public void ButtonTaskIsComplete()
        {
            _isMyTaskRunning = false;
            RaiseCanExecuteChanged();
        }


    }
}

可能不是一個完美的選擇,但可能會為您提供一個可能的包裝解決方案。

您提到的RelayCommandExtension也有類似的問題。

存在與此相關的問題 Github 那里發布了以下解決方案

RelayCommandExtensions.cs添加以下行:

notifiers.Add(obj, notifier);

OnIsCommandUpdateEnabledChanged(...)方法,使其看起來像這樣:

// Ensure a notifier is enabled so that we can monitor for changes to the command
// property in the future. This is also needed in case this attached property is
// set before the binding engine has actually resolved the target command instance.
if (!notifiers.TryGetValue(obj, out _))
{
    PropertyChangeNotifier notifier = new(obj, nameof(ICommandSource.Command));

    notifier.PropertyChanged += (_, _) => ToggleIsCommandUpdateEnabled(obj);
    
    notifiers.Add(obj, notifier);
}

這對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM