Я настоятельно рекомендую взглянуть на ReactiveUI - инфраструктура пользовательского интерфейса, основанная на Rx - вам не нужно использовать все ее функции, такие как встроенное внедрение зависимостей или расположение представления, но это также очень круто , В этом случае не стоит изобретать колесо.
Он имеет реализацию ICommand, которая не только поддерживает асинхронную работу из коробки, но также позволяет командам возвращать вещи (ОЧЕНЬ полезно) и заботится об отключении кнопки при выполнении.
Он также поставляется с DynamicData - лекарство от всех проблем, связанных с коллекциями.
Итак, большинство базовых c примеров будут:
TestCommand = ReactiveCommand.CreateFromTask<int>(async paramater =>{
var result = await DoStuff(parameter); // ConfigureAwait(false) might be helpful in more complex scenarios
return result + 5;
}
TestCommand.Log(this) // there is some customization available here
.Subscribe(x => SomeVmProperty = x;); // this always runs on Dispatcher out of the box
TestCommand.ThrownExceptions.Log(this).Subscribe(ex => HandleError(ex));
this.WhenAnyValue(x => x.SearchText) // every time property changes
.Throttle(TimeSpan.FromMilliseconds(150)) // wait 150 ms after the last change
.Select(x => SearchText)
.InvokeCommand(Search); // we pass SearchText as a parameter to Search command, error handling is done by subscribing to Search.ThrownExceptions. This will also automatically disable all buttons bound to Search command
Что еще более полезно, я думаю, это возможность подписаться в коде View позади.
// LoginView.xaml.cs
ViewModel.Login.Where(x => !x.Success).Subscribe(_ =>{
PasswordBox.Clear();
PasswordBox.Focus();
});