c# - 使用MVVM按下按钮时如何调用异步方法?
问题描述
我现在一直在寻找一种将命令绑定到按钮的方法,该按钮应该在我的 ViewModel 中提示一个异步函数,并且应该启动调用并能够取消调用。我查看了 Stephen Cleary 的教程并尝试将它们转换为我的需要,尽管命令管理器在 AsyncCommandBase 的当前上下文中不存在,当您查看他的 git 项目代码时,它与他的教程中的完全不同...我不知道从哪里继续得到我的答案,所以我们开始吧。我有一个 ViewModel 应该运行一个异步的函数并且应该通过单击一个按钮来运行?有没有办法在不编写新库的情况下完成这项工作?我做了一个看起来像这样的界面......
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using System.Threading.Tasks;
namespace Data
{
public interface IAsyncCommand : ICommand
{
Task ExcecuteAsync(Object parameter);
}
}
和一个看起来像这样的基本命令类
using System;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Data
{
/// <summary>
/// An async command that implements <see cref="ICommand"/>, forwarding <see cref="ICommand.Execute(object)"/> to <see cref="IAsyncCommand.ExecuteAsync(object)"/>.
/// </summary>
public abstract class AsyncCommandBase : IAsyncCommand
{
/// <summary>
/// The local implementation of <see cref="ICommand.CanExecuteChanged"/>.
/// </summary>
private readonly ICanExecuteChanged _canExecuteChanged;
/// <summary>
/// Creates an instance with its own implementation of <see cref="ICommand.CanExecuteChanged"/>.
/// </summary>
protected AsyncCommandBase(Func<object, ICanExecuteChanged> canExecuteChangedFactory)
{
_canExecuteChanged = canExecuteChangedFactory(this);
}
/// <summary>
/// Executes the command asynchronously.
/// </summary>
/// <param name="parameter">The parameter for the command.</param>
public abstract Task ExecuteAsync(object parameter);
/// <summary>
/// The implementation of <see cref="ICommand.CanExecute(object)"/>.
/// </summary>
/// <param name="parameter">The parameter for the command.</param>
protected abstract bool CanExecute(object parameter);
/// <summary>
/// Raises <see cref="ICommand.CanExecuteChanged"/>.
/// </summary>
protected void OnCanExecuteChanged()
{
_canExecuteChanged.OnCanExecuteChanged();
}
event EventHandler ICommand.CanExecuteChanged
{
add { _canExecuteChanged.CanExecuteChanged += value; }
remove { _canExecuteChanged.CanExecuteChanged -= value; }
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute(parameter);
}
async void ICommand.Execute(object parameter)
{
await ExecuteAsync(parameter);
}
}
}
该链接指向他的教程,如果您需要它,请告诉我,我会尽快发送他的 git 代码!:D
解决方案
我不明白你为什么需要创建一个异步版本的RelayCommand
. 您可以在执行侦听取消令牌的命令时简单地运行异步方法。就像是:
你的命令:public ICommand DoSomethingCommand { get; set; }
在某处实例化您的命令:DoSomethingCommand = new RelayCommand(DoSomething);
以及该方法的一个示例DoSomething
:
private async void DoSomething()
{
using (var cancellationToken = new CancellationTokenSource())
{
await Task.Run(() =>
{
for(i = 0; i < 100; i++)
{
if (cancellationToken.IsCancellationRequested) break;
//Here's where something is done.
}
});
}
}
正常绑定:<Button Content="Do Something" Command="{Binding DoSomethingCommand}"/>
以防万一您需要它,RelayCommand
您可以使用以下简单方法:
public class RelayCommand : ICommand
{
public RelayCommand(Action execute, Func<bool> canExecute)
{
CommandManager.RequerySuggested += (s, e) => CanExecuteChanged(s, e);
CanExecuteDelegate = canExecute;
ExecuteDelegate = execute;
}
public RelayCommand(Action execute) : this(execute, () => true) { }
public event EventHandler CanExecuteChanged = delegate { };
public Func<bool> CanExecuteDelegate { get; set; }
public Action ExecuteDelegate { get; set; }
public bool CanExecute(object parameter) => CanExecuteDelegate();
public void Execute(object parameter) => ExecuteDelegate();
}
我确实建议使用适当的库,例如 MVVM Light。希望这可以帮助。
推荐阅读
- python - 不和谐.py | 事件冷却时间
- sql - 如何根据 ID 和名称对总支出进行分组
- flutter - 在 Flutter 的所有页面中导入一次并使用库
- javascript - Tensorflow JS - 加载模型,TypeError:未定义不是对象(评估'inboundNodesData.forEach')
- .net - 您可以使用 .NET MAUI 和 blazor 开发网页并针对 web、ios、android 和 windows 吗?
- reactjs - 生产 React 应用程序失败并出现缩小的 React 错误 #321
- python-3.x - 滚动以使用 selenium 和 beautifulsoup 抓取更多细节
- python - 如何将 Flask Web 应用程序和 Windows Forms App (C#) 组合成一个 .EXE 文件/应用程序?
- android-studio - 无法使字段私有最终 java.lang.String java.io.File.path 可访问
- r - 基于存在于带有 R 的尖端标签中的字符串来标记系统发育中的内部节点