The Model-View-View Model (MVVM) pattern is more popular than ever and is built into the Visual Studio templates for creating Windows Store apps. Developers familiar with Silverlight already encountered the platform shift to using asynchronous operations because it was impossible to generate a WCF client with synchronous methods. The Windows Runtime (WinRT) takes this further by dictating any operation that may potentially take longer than 50ms to complete should be asynchronous.
How does the MVVM pattern handle asynchronous operations, when the command interface ICommand only exposes synchronous methods?
namespace System.Windows.Input {
public interface ICommand
{
event EventHandler CanExecuteChanged;
bool CanExecute(object parameter);
void Execute(object parameter);
} }
Now consider a simple implementation of a command we’ll call an ActionCommand because it allows you to specify a delegate to perform and action when it is invoked. It also provides a predicate to condition the command and a public method to notify the command when the conditions for the predicate have changed.
namespace MyApp.Common {
using System;
using System.Windows.Input;
public class ActionCommand : ICommand
{
private readonly Action action;
private readonly Func<bool> condition;
public ActionCommand()
{
this.action = delegate { };
this.condition = () => true;
}
public ActionCommand(Action action)
{
this.action = action;
this.condition = () => true;
}
public ActionCommand(Action action, Func<bool> condition)
{
this.action = action;
this.condition = condition;
}
public event EventHandler CanExecuteChanged = delegate { };
public void RaiseExecuteChanged()
{
this.CanExecuteChanged(this, EventArgs.Empty);
}
public bool CanExecute(object parameter)
{
return this.condition();
}
public void Execute(object parameter)
{
this.action();
}
} }
As you can see, there is no Task in the implementation of ICommand, nor any asynchronous code. As you are also aware, WinRT requires asynchronous code when you are performing various operations including a dialog. Here is an example of code that copies text and HTML to the clipboard and then shows a dialog to the end user they must confirm to acknowledge the copy was successful. The method is asynchronous.
private async Task Copy() {
var package = new DataPackage();
package.SetText(this.DataManager.CurrentPage.Text);
package.SetHtmlFormat(HtmlFormatHelper.CreateHtmlFormat
(this.DataManager.CurrentPage.Html));
Clipboard.SetContent(package);
var dialog = new MessageDialog(
"The web page was successfully copied to the clipboard.");
await dialog.ShowAsync(); }
Now you have to wire it to the command implementation that is not asynchronous. How can you? Fortunately, the magic that is asynchronous code is able to combine forces with lambda expressions to enable you to handle asynchronous code “on the fly.” Here is the code to wire-up the command to call the Copy method asynchronously:
this.CopyCommand = new ActionCommand(
async () => await this.Copy(),
() => this.CopyEnabled);
That’s it. The action itself may be implemented as an asynchronous operation simply by invoking the async keyword and using the await operator. That’s how easy it is! While you should typically declare your interface consistently – for example, declaring them to return a Task when they should be implemented asynchronously – using this technique you can apply an asynchronous operation to the existing contract when needed. This means your commands can be asynchronous if and when needed, in full compliance with the WinRT guidelines.