Wintellect  

Browse by Tags

All Tags » asynchronous   (RSS)

I noticed on the forums there are a lot of users not comfortable with asynchronous programming who struggle a bit in Silverlight with getting their arms around the concept of a dialog box. In other environments, you can simply shoot out a dialog, wait for the response, and continue. In Silverlight, of course, the action is asynchronous. I would argue it should be this way most of the time.

The problem is that many people tend to take the approach of trying to force the process into a synchronous one, instead of changing the way they think and approach the application. There is a reason why processes are asynchronous in Silverlight. There is one main UI thread, and a blocking process would block the entire thread and effectively freeze the Silverlight application. Having the process asynchronous allows you to continue to render graphics elements, perform actions in the background, even display a soothing animation while you await the user's response.

I spoke to a more highly decoupled approach in a post awhile ago that was more an experiment with the event aggregator: Decoupled Child Window Dialogs with Silverlight and PRISM. Here, I want to show the more straightforward approach.

The first step is to choose what the dialog will be displayed with. In Silverlight, the ChildWindow makes perfect sense because it is a modal dialog that appears, waits for the user response, and then saves the response. We'll create a new child window and call it Dialog.xaml. It looks like this:

<controls:ChildWindow x:Class="SimpleDialog.Dialog"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           Width="400" Height="300" 
           Title="{Binding Title}">
    <Grid x:Name="LayoutRoot" Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock TextWrapping="Wrap" Grid.Row="0" Text="{Binding Message}"/>
        <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
        <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
    </Grid>
</controls:ChildWindow>

You'll notice I made very few changes from the provided template. The key here is that I changed the title to bind with the Title property, and added a text block to display a message from the Message property.

Because this is a simple dialog box, I really feel a view model is overkill. Some purists will insist on this but I argue the functionality is simple enough that we don't need the extra overhead. We'll be using an interface to the solution down the road that we can easily unit test, and this makes the dialog function (which lives entirely in the UI) a self-contained implementation.

Next, I made a few changes to the code behind:

public partial class Dialog : ChildWindow
{
    public Action<bool> CloseAction { get; set; }

    public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
        "Message",
        typeof(string),
        typeof(Dialog),
        null);


    public string Message
    {
        get { return GetValue(MessageProperty).ToString(); }
        set { SetValue(MessageProperty, value); }
    }

    public Dialog()
    {
        InitializeComponent();
        DataContext = this;
    }        

    public Dialog(bool allowCancel)
        : this()
    {
        CancelButton.Visibility = allowCancel ? Visibility.Visible : Visibility.Collapsed;
    }

    private void OKButton_Click(object sender, RoutedEventArgs e)
    {
        this.DialogResult = true;            
    }

    private void CancelButton_Click(object sender, RoutedEventArgs e)
    {
        this.DialogResult = false;           
    }
}

Again, not too many changes here. I added the Message property as a dependency property, and in the constructor I set the data context to itself. This allows me to bind to the title and message. This allows us to simply set the message on the dialog and have it appear. I also added an action for it to retain when closed. This will store a callback so that it can notify the host of the user's final actions. Finally, there is a method that conditions whether or not there is the option for a cancel button. For alerts, we'll simply show an OK button. For confirmations, we'll show the Cancel button as well.

Next is a simple interface to the dialog. Nothing in our application should know or care how the dialog is displayed. There is simply a mechanism to display the dialog and possibly acquire a response. The interface looks like this:

public interface IDialogService
{
    void ShowDialog(string title, string message, bool allowCancel, Action<bool> response);
}

In our simple demonstration, I'm allowing for a title, a message, whether or not you want to show the cancel button for confirmations, and then an action to call with the response. With this simple interface we have all we need to wire in unit tests for services and controls that rely on the dialog. You can create your own mock object that implements the IDialogService interface and returns whatever response you want to stage for the unit test.

In the production application, we'll need to show a real dialog. Here is the class that handles it:

public class DialogService : IDialogService
{
    #region IDialogService Members

    public void ShowDialog(string title, string message, bool allowCancel, Action<bool> response)
    {
        var dialog = new Dialog(allowCancel) {Title = title, Message = message, CloseAction = response};
        dialog.Closed += DialogClosed;
        dialog.Show();
    }

    static void DialogClosed(object sender, EventArgs e)
    {
        var dialog = sender as Dialog;
        if (dialog != null)
        {
            dialog.Closed -= DialogClosed; 
            dialog.CloseAction(dialog.DialogResult == true);
        }
    }

    #endregion
}

This is fairly straightforward. When called, we'll create an instance of the dialog and set the various properties, including the callback. We wire into the closed event. Whether the user responds by clicking a button or closing the dialog, this event is fired.

There is a reason why we are using the snippet DialogResult == true. The result is null-able, so we cannot simply refer to the value itself and make a true/false decision (null, by definition, is unknown). So only if the user explicitly provides a true response by clicking the OK button will the expression evaluate to true. Otherwise, we assume false and call back with the response.

There is also a very important step here that is important to recognize. Many beginners fail to catch this subtle step and end up with memory leaks. When the closed event fires, the dialog box effectively closes. Typically, there would be no more references to it (it is no longer in the visual tree) and it can be cleaned up by garbage collection. However, there is a fatal mistake you can make that will result in the dialog box never going away.

That mistake has to do with how events work. When we register the closed event, the thought process is often that the dialog box has an event, and therefore knows to call back to the dialog service. This is flawed, however. A reference exists from the dialog service to the dialog box. The dialog service effectively "listens" for the event, and when it is raised, will respond. We must unregister the event like this:

dialog.Closed -= DialogClosed;

Otherwise, the reference remains and garbage collection will never claim the dialog box resource. In a long running application, this could prove to be a serious flaw. This line is not included in the code sample download. I encourage you to run with windbg or even step through debug in Visual Studio and watch the object graphs and reference counts as you fire multiple dialogs. Then, add the line of code above and re-run it to see the difference when you appropriately unregister the event.

To demonstrate the use of the service, I put together a quick little page with a few buttons and a text block:

<UserControl x:Class="SimpleDialog.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
  <Grid x:Name="LayoutRoot">
        <StackPanel Orientation="Vertical">
            <Button x:Name="ToggleEnabled" 
                    HorizontalAlignment="Center"
                    Margin="5" Width="Auto" Content="Disable Dialog Button" Click="ToggleEnabled_Click"/>
            <Button x:Name="DialogButton" 
                    HorizontalAlignment="Center"
                    Margin="5" Width="Auto" Content="DialogButton" Click="DialogButton_Click"/>
            <TextBlock x:Name="TextDialog" 
                       HorizontalAlignment="Center"
                       Margin="5" Width="Auto" Text="Result Will Show Here"/>
        </StackPanel>
    </Grid>
</UserControl>

The first button is a toggle to enable or disable the second button. It shows how to receive a response and act based on the user input. If the user confirms, the button is toggled to enabled or disabled. If the user cancels or closes the dialog, the state of the button remains the same. The second button raises a dialog, and simply shows the result. Because it is an alert dialog, we know a false response indicates the user closed the window instead of clicking OK.

Here is the code behind:

public partial class MainPage : UserControl
{
    private bool _toggleState = true;
    private readonly IDialogService _dialog = new DialogService();

    public MainPage()
    {
        InitializeComponent();
    }

    private void ToggleEnabled_Click(object sender, RoutedEventArgs e)
    {
        _dialog.ShowDialog(
            _toggleState ? "Disable Button" : "Enable Button",
            _toggleState
                ? "Are you sure you want to disable the dialog button?"
                : "Are you sure you want to enable the dialog button?",
            true,
            r =>
                {
                    if (r)
                    {
                        _toggleState = !_toggleState;
                        DialogButton.IsEnabled = _toggleState;
                        ToggleEnabled.Content = _toggleState ? "Disable Dialog Button" : "Enable Dialog Button";
                    }
                });
    }

    private void DialogButton_Click(object sender, RoutedEventArgs e)
    {
        _dialog.ShowDialog(
            "Confirm This",
            "You have to either close the window or click OK to confirm this.",
            false,
            r => { TextDialog.Text = r ? "You clicked OK." : "You closed the dialog."; });
    }
}

Notice that in the click events, we call to the dialog service and pass it anonymous methods for the return types. We could point to real methods on the class as well. The important part is to change your thought process from synchronous step one => wait => step two to asynchronous step one => delegate to step two, then step two is called when ready.

In a production application, instead of creating an instance of the dialog box, we would either register it with a container:

Container.RegisterInstance<IDialogService>(Container.Resolve<DialogService>());

And inject it in a constructor, or use something like MEF and import the dialog service:

[Import]
public IDialogService Dialog { get; set; }

We would simply flag the implementation as the export or use the InheritedExport attribute on the interface itself.

Click here to download the source code for this example.

Jeremy Likness

This post explores a way to encapsulate web service calls from Silverlight in a way that is easy to use and understand.

As anyone who works with Silverlight knows, Silverlight forces web service calls to be asynchronous. There is a good reason for this, which I won't get into with this post. What I would like to do is demonstrate an approach that advocates a clean separation of the internals of the service from the application that is consuming it.

First, I am assuming you understand web services and WCF. I assume you've called services from Silverlight, and are aware of the nuances of configuring the endpoint, etc. I am also going to assume you are familiar with some frameworks such as Prism, MEF, Caliburn, etc that advocate clean separation of concerns and modular design.

Let's assume I have a service on my web page that is a calculator (oh, where did I get that idea?) It looks something like this:


[ServiceContract(Namespace = "http://www.wintellect.com/sample")]    
public interface ICalculatorService
{
    [OperationContract]
    long Multiply(int x, int y);
}

Simple, correct? The first thing I'm going to do is to create a similar interface on my Silverlight client. This interface will hide the details of how the service is connected and wired. I also want to make it easier to deal with the asynchronous nature of the calls. I've seen some pretty exotic implementations to try to make an asynchronous call look synchronous, and don't quite understand why we'd want to do it. Instead, let's just define a contract like this somewhere in the Silverlight application that is "seen" globally:


public interface ICalculator 
{
   void Multiply(int x, int y, Action<long> result); 
}

As you can see, it's a simple void method ... in fact, all methods we use to abstract the asynchronous calls will most likely be void. But the key is last parameter. This delegate allows me to specify how I want to deal with the result.

Now I create a project that is solely used to implement ICalculator and connect with the web service. First, if you haven't read my post about abstracting WCF service calls, be sure to read it: Abstracting WCF Service Calls in Silverlight. It explains how I use a base class to avoid having to change the ServiceReferences.ClientConfig file everytime I deploy an application, and also will give you the concept for the BaseService class you see below.


public class CalculatorService : BaseService<CalculatorServiceClient,ICalculatorService>, ICalculator
{
    public CalculatorService()
    {
        _GetClientChannel().MultiplyCompleted += new EventHandler<MultiplyCompletedEventArgs>(CalculatorService_MultiplyCompleted);
    }        

    #region Event handlers

    void CalculatorService_MultiplyCompleted(object sender, MultiplyCompletedEventArgs e)
    {
        Action<long> result = e.UserState as Action<long>;
        if (result != null)
        {
            result(e.Result); 
        }
    }

    #endregion 

    #region ICalculator Members

    public void Multiply(int x, int y, Action<long> result)
    {
        _GetClientChannel().MultiplyAsync(x, y, result);
    }

    #endregion
}

The base class preps the channel and credentials, etc for me. In the constructor of the implementation, I simply register for the completion event for the call. When a consumer of the service makes a call, the consumer provides a delegate to call back to when the service is done. This is passed in the user state, then cast back to an action and called once the service returns. If you wanted to have error handling, you'd just extend the action delegate to have an error-related parameter and check the e.Error when the call completed.

Now we can put it into use. In my bootstrapper, I'll bind the service to the contract like this:


Container.RegisterType<ICalculator,CalculatorService>(new ContainerControlledLifetimeManager());
            

Now I can throw a view model together that looks something like this:


public class CalculatorViewModel : INotifyPropertyChanged
{

    private bool _busy = false;

    public bool BusyState
    {
        get { return _busy; }
        set
        {
            if (!value.Equals(_busy))
            {
                _busy = value;
                OnPropertyChanged("BusyState");
                CalculateCommand.RaiseCanExecuteChanged();
            }
        }
    }

   public DelegateCommand<object> CalculateCommand { get; set; } 

    public CalculatorViewModel(ICalculator calculator)
    {
        Calculator = calculator;
        CalculateCommand = new DelegateCommand<object>(o => CommandCalculate(),
            o => !BusyState);
    }

    public ICalulator Calculator { get; set; }

    private int _x;

    public int X
    {
        get { return _x; }
        set
        {
            if (!value.Equals(_x))
            {
                _x = value;
                OnPropertyChanged("X"); 
            }
        }
    }

     private int _y;

    public int Y
    {
        get { return _y; }
        set
        {
            if (!value.Equals(_y))
            {
                _y = value;
                OnPropertyChanged("Y"); 
            }
        }
    }

    private long _answer;

    public long Answer
    {
        get { return _answer; }
        set
        {
            if (!value.Equals(_answer))
            {
                _answer = value;
                OnPropertyChanged("Answer"); 
            }
        }
    }

    public void CommandCalculate()
    {
        BusyState = true;
        Calculator.Multiply(_x, _y, answer => {
              BusyState = false;
              Answer = answer;
         }); 
    }

    private void OnPropertyChanged(string property)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(property));
        }
    }

    #endregion 

    #region INotifyPropertyChanged Members

   public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

Now I can simply data bind my XAML to the X, Y, and Answer properties, and bind a button to the Click command. The button will even disable itself while the client is waiting on the server to return the answer. As you can see, the implementation is very straightforward and I don't have to worry about how the call happens. In fact, using this type of abstraction, I could easily wire in a mock class to satisfy the service for testing like this... or maybe decide that a web service for multiplication is overkill and just satisy the contract locally:


public class MockCalculator : ICalculator 
{
   public void Multiply(int x, int y, Action<long> result) 
   {
      result(x*y);
   }
}

While the Action command is really a different way of expressing a delegate, it also makes the intent of the code clear and allows for a clean separation of mechanism from result when dealing with asynchronous calls.

Jeremy Likness