前段时间我决定学习MVVM和async / await。 使用实体框架代码优先,我的应用程序可以将新用户写入数据库。 在MSDN async databinding article我得到了测试异步绑定类NotifyTaskCompletion.cs(重命名为TaskPropertyWatcher.cs),用于从数据库异步加载用户。这班工作。 之后阅读second article。 我从文章中复制粘贴完整的异步类,将AsyncCommand绑定到按钮。
问题:单击绑定按钮时出现NullReferenceException。 这不是编译器错误。 也许有人可以帮助这个“神奇”?
AsyncCommandBase类错误调试信息:
Example solution from MSDN(first item at page)工作正常......
我的DAL AddUser方法:
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);
}
}
P.S抱歉我的英语不好。在此先感谢您的帮助!
答案 0 :(得分:2)
您收到NullReferenceException
,因为TaskCompletion
为null
。
第二篇(异步命令)文章的原始代码下载中存在错误,如果在构造NotifyTaskCompletion
之前完成任务,则TaskCompletion
将为空NotifyTaskCompletion
第一篇文章中没有这个错误(根本没有任何TaskCompletion
),并且在不久前修复了第二篇文章。我建议你重新下载它。