C# MVVM AsyncCommand NullReference

C# MVVM AsyncCommand NullReference,c#,.net,wpf,asynchronous,mvvm,C#,.net,Wpf,Asynchronous,Mvvm,不久前,我决定学习MVVM和async/await。 首先使用实体框架代码,我的应用程序可以将新用户写入数据库。 在测试时,我获得了异步绑定类NotifyTaskCompletion.cs(重命名为TaskPropertyWatcher.cs),用于从数据库异步加载用户。这个班在工作。 在那之后被宣读。 我从文章中复制粘贴完整的异步类,将AsyncCommand绑定到按钮 问题:单击绑定按钮时出现NullReferenceException。 这不是编译器错误。 也许有人能帮上忙 AsyncCo

不久前,我决定学习MVVM和async/await。 首先使用实体框架代码,我的应用程序可以将新用户写入数据库。 在测试时,我获得了异步绑定类NotifyTaskCompletion.cs(重命名为TaskPropertyWatcher.cs),用于从数据库异步加载用户。这个班在工作。 在那之后被宣读。 我从文章中复制粘贴完整的异步类,将AsyncCommand绑定到按钮

问题:单击绑定按钮时出现NullReferenceException。 这不是编译器错误。 也许有人能帮上忙

AsyncCommandBase类错误调试信息:

AsyncCommand类错误调试信息:

工作完美

我的用户方法:

   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:等待
任务
任务完成
之间有一个很大的区别:在出现错误的情况下,等待
任务
将重新引发任务的异常,导致应用程序崩溃而不是