C# MVVM AsyncCommand NullReference
不久前,我决定学习MVVM和async/await。 首先使用实体框架代码,我的应用程序可以将新用户写入数据库。 在测试时,我获得了异步绑定类NotifyTaskCompletion.cs(重命名为TaskPropertyWatcher.cs),用于从数据库异步加载用户。这个班在工作。 在那之后被宣读。 我从文章中复制粘贴完整的异步类,将AsyncCommand绑定到按钮 问题:单击绑定按钮时出现NullReferenceException。 这不是编译器错误。 也许有人能帮上忙 AsyncCommandBase类错误调试信息: AsyncCommand类错误调试信息: 工作完美 我的用户方法:C# MVVM AsyncCommand NullReference,c#,.net,wpf,asynchronous,mvvm,C#,.net,Wpf,Asynchronous,Mvvm,不久前,我决定学习MVVM和async/await。 首先使用实体框架代码,我的应用程序可以将新用户写入数据库。 在测试时,我获得了异步绑定类NotifyTaskCompletion.cs(重命名为TaskPropertyWatcher.cs),用于从数据库异步加载用户。这个班在工作。 在那之后被宣读。 我从文章中复制粘贴完整的异步类,将AsyncCommand绑定到按钮 问题:单击绑定按钮时出现NullReferenceException。 这不是编译器错误。 也许有人能帮上忙 AsyncCo
public static async Task AddUser(User usr)
{
using (var cntx = new ServiceDBContext())
{
cntx.Users.Add(usr);
await cntx.SaveChangesAsync();
}
}
实体模型:
[Table("Users")]
public partial class User
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ClientId { get; set; }
[StringLength(60)]
public string ClientType { get; set; }
[StringLength(160)]
public string ClientName { get; set; }
[StringLength(60)]
public string Mobile { get; set; }
[StringLength(50)]
public string EMail { get; set; }
}
我的ViewModel部件:
public CustomerAddViewModel()
{
AddClient = AsyncCommand.Create(() => DAL.DbService.AddUser(Client));
}
private User _user = new User();
public User Client
{
get
{
return _user;
}
set {
_user = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged([CallerMemberName]string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
视图构造函数:
public CustomerAddView()
{
DataContext = new CustomerAddViewModel();
InitializeComponent();
}
我的视图数据绑定部分:
<Button Command="{Binding AddClient}" x:Name="button" Content="Add user" HorizontalAlignment="Left" Margin="5,185,0,0" VerticalAlignment="Top" Width="365" Height="26"/>
<TextBox Text="{Binding Client.ClientName}" HorizontalAlignment="Left" Margin="5,34,0,0" VerticalAlignment="Top" Width="365" ></TextBox>
<TextBox Text="{Binding Client.ClientType}" HorizontalAlignment="Left" Margin="5,34,0,0" VerticalAlignment="Top" Width="365" ></TextBox>
<TextBox Text="{Binding Client.EMail}" HorizontalAlignment="Left" Margin="5,34,0,0" VerticalAlignment="Top" Width="365" ></TextBox>
<TextBox Text="{Binding Client.Phone}" HorizontalAlignment="Left" Margin="5,34,0,0" VerticalAlignment="Top" Width="365" ></TextBox>
MSDN代码:
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync(object parameter);
}
public abstract class AsyncCommandBase : IAsyncCommand
{
public abstract bool CanExecute(object parameter);
public abstract Task ExecuteAsync(object parameter);
public async void Execute(object parameter)
{
await ExecuteAsync(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
protected void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
public class AsyncCommand<TResult> : AsyncCommandBase, INotifyPropertyChanged
{
private readonly Func<CancellationToken, Task<TResult>> _command;
private readonly CancelAsyncCommand _cancelCommand;
private TaskPropertyWatcher <TResult> _execution;
public AsyncCommand(Func<CancellationToken, Task<TResult>> command)
{
_command = command;
_cancelCommand = new CancelAsyncCommand();
}
public override bool CanExecute(object parameter)
{
return Execution == null || Execution.IsCompleted;
}
public override async Task ExecuteAsync(object parameter)
{
_cancelCommand.NotifyCommandStarting();
Execution = new TaskPropertyWatcher<TResult>(_command(_cancelCommand.Token));
RaiseCanExecuteChanged();
await Execution.TaskCompletion;
_cancelCommand.NotifyCommandFinished();
RaiseCanExecuteChanged();
}
public ICommand CancelCommand
{
get { return _cancelCommand; }
}
public TaskPropertyWatcher<TResult> Execution
{
get { return _execution; }
private set
{
_execution = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
private sealed class CancelAsyncCommand : ICommand
{
private CancellationTokenSource _cts = new CancellationTokenSource();
private bool _commandExecuting;
public CancellationToken Token { get { return _cts.Token; } }
public void NotifyCommandStarting()
{
_commandExecuting = true;
if (!_cts.IsCancellationRequested)
return;
_cts = new CancellationTokenSource();
RaiseCanExecuteChanged();
}
public void NotifyCommandFinished()
{
_commandExecuting = false;
RaiseCanExecuteChanged();
}
bool ICommand.CanExecute(object parameter)
{
return _commandExecuting && !_cts.IsCancellationRequested;
}
void ICommand.Execute(object parameter)
{
_cts.Cancel();
RaiseCanExecuteChanged();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
}
public static class AsyncCommand
{
public static AsyncCommand<object> Create(Func<Task> command)
{
return new AsyncCommand<object>(async _ => { await command(); return null; });
}
public static AsyncCommand<TResult> Create<TResult>(Func<Task<TResult>> command)
{
return new AsyncCommand<TResult>(_ => command());
}
public static AsyncCommand<object> Create(Func<CancellationToken, Task> command)
{
return new AsyncCommand<object>(async token => { await command(token); return null; });
}
public static AsyncCommand<TResult> Create<TResult>(Func<CancellationToken, Task<TResult>> command)
{
return new AsyncCommand<TResult>(command);
}
}
公共接口IAsyncCommand:ICommand
{
任务执行同步(对象参数);
}
公共抽象类AsyncCommandBase:IAsyncCommand
{
公共抽象boolcanexecute(对象参数);
公共抽象任务ExecuteAsync(对象参数);
公共异步void Execute(对象参数)
{
等待执行同步(参数);
}
公共事件事件处理程序CanExecuteChanged
{
添加{CommandManager.RequerySuggested+=value;}
删除{CommandManager.RequerySuggested-=value;}
}
受保护的无效RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequestSuggested();
}
}
公共类AsyncCommand:AsyncCommandBase,INotifyPropertyChanged
{
私有只读Func_命令;
私有只读CancelAsyncCommand\u cancelCommand;
私有TaskPropertyWatcher\u执行;
公共异步命令(Func命令)
{
_命令=命令;
_cancelCommand=新的CancelAsyncCommand();
}
公共覆盖布尔CanExecute(对象参数)
{
返回执行==null | | Execution.IsCompleted;
}
公共覆盖异步任务ExecuteAsync(对象参数)
{
_cancelCommand.NotifyCommandStarting();
执行=新建TaskPropertyWatcher(_命令(_cancelCommand.Token));
RaiseCanExecuteChanged();
等待执行。任务完成;
_cancelCommand.NotifyCommandFinished();
RaiseCanExecuteChanged();
}
公共ICommand取消命令
{
获取{return\u cancelCommand;}
}
公共TaskPropertyWatcher执行
{
获取{return\u execution;}
专用设备
{
_执行=价值;
OnPropertyChanged();
}
}
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(handler!=null)handler(这是新的PropertyChangedEventArgs(propertyName));
}
私有密封类CancelAsyncCommand:ICommand
{
私有CancellationTokenSource _cts=new CancellationTokenSource();
私人布卢;
public CancellationToken令牌{get{return}cts.Token;}
public void NotifyCommandStarting()
{
_commandExecuting=true;
如果(!\u cts.iscancellationrequest)
返回;
_cts=新的CancellationTokenSource();
RaiseCanExecuteChanged();
}
public void NotifyCommandFinished()
{
_commandExecuting=false;
RaiseCanExecuteChanged();
}
bool ICommand.CanExecute(对象参数)
{
返回&u commandExecuting&!\u cts.IsCancellationRequested;
}
void ICommand.Execute(对象参数)
{
_cts.Cancel();
RaiseCanExecuteChanged();
}
公共事件事件处理程序CanExecuteChanged
{
添加{CommandManager.RequerySuggested+=value;}
删除{CommandManager.RequerySuggested-=value;}
}
private void RaiseCanExecuteChanged()的定义
{
CommandManager.InvalidateRequestSuggested();
}
}
}
公共静态类async命令
{
公共静态异步命令创建(Func命令)
{
返回新的AsyncCommand(async=>{await command();返回null;});
}
公共静态异步命令创建(Func命令)
{
返回新的AsyncCommand(=>command());
}
公共静态异步命令创建(Func命令)
{
返回新的AsyncCommand(异步令牌=>{await command(令牌);返回null;});
}
公共静态异步命令创建(Func命令)
{
返回新的异步命令(命令);
}
}
对不起,我的英语不好。提前感谢您的帮助 您将获得一个
NullReferenceException
,因为TaskCompletion
是null
第二篇(异步命令)文章的原始代码下载中有一个bug,如果任务在构建NotifyTaskCompletion
之前完成,则NotifyTaskCompletion
将有一个空TaskCompletion
这个bug在第一篇文章中不存在(它根本没有任何
任务完成
),并且在不久前的第二篇文章中被修复。我建议您重新下载。谢谢!但我在AsyncCommand中使用了另一种方式。。。等待执行任务_cancelCommand.NotifyCommandFinished();我用不同的方法测试了它的工作原理!属性样式正在工作,在异步命令中,等待任务属性也在工作。另外,你的文章太完美了!谢谢。请使用NotifyTaskCompletion从第一篇文章开始等待执行。Task@user1576474:等待任务
和任务完成
之间有一个很大的区别:在出现错误的情况下,等待任务
将重新引发任务的异常,导致应用程序崩溃而不是