Junior Mayhe
Junior Mayhe

Reputation: 16411

Is there a better way to update UI Element with Dispatcher?

I'm a newbie with WCF services, and I'm trying to figure out if is there a better way to update a WPF UI element (like a Label control) when I'm calling asynchronously my WCF service.

Here's a piece of code:

    private void button1_Click(object sender, RoutedEventArgs e)
    {

        int result;
        CalculatorServiceClient proxy = new CalculatorServiceClient();
        AsyncCallback addOperation = (async_result) =>
        {
            result = proxy.EndAdd(async_result);

            Dispatcher.Invoke(DispatcherPriority.Normal,
                  new Action(
                      delegate()
                      {
                        label1.Content = result.ToString();
                      }
                  )
            );
            proxy.Close();
        };
        proxy.BeginAdd(Convert.ToInt32(txtNumber1.Text), Convert.ToInt32(txtNumber2.Text), addOperation, null);

    }

As you can see, I'm updating label1.Content with an asynchronous result, obtained by an AsyncCallback.

My question is, is there a better or more correct way to refresh an UI control inside this asynchronous callback operation?

thanks in advance!

Upvotes: 1

Views: 9357

Answers (2)

Oleg Mihailik
Oleg Mihailik

Reputation: 2590

Can be done even shorter:

using (var proxy = new CalculatorServiceClient())
{
    proxy.BeginAdd(
         Convert.ToInt32(txtNumber1.Text),
         Convert.ToInt32(txtNumber2.Text),
         (asyncResult) =>
             {
                 int result = proxy.EndAdd(asyncResult);
                 Dispatcher.BeginInvoke(
                   (Action) () => { label1.Content = result; });
             },
         null);
}

The trick is, Invoke/BeginInvoke does not mean you have to pass parameters explicitly, compiler works it out anyway.

And you don't want to use Invoke, because it ties the background thread for no need.

Upvotes: 1

Yvo
Yvo

Reputation: 19263

The Dispatcher.Invoke is a good way of updating your UI. UI actions have to be performed by the UI Thread, the Dispatcher takes care of this.

You can make your code a bit shorter by using Lambda expressions:

Dispatcher.Invoke((Action<string>) ((data) => { label1.Content = data; }));

I would also suggest putting the proxy in a Using statement, so that would make it:

int result = 0;
using (CalculatorServiceClient proxy = new CalculatorServiceClient()) {
    AsyncCallback callback = new AsyncCallback((asyncResult) => {
        result = proxy.EndAdd(asyncResult);
        Dispatcher.Invoke((Action<string>) ((data) => { label1.Content = data; }));
    });

    proxy.BeginAdd(Convert.ToInt32(txtNumber1.Text), Convert.ToInt32(txtNumber2.Text), callback, null);
}

Or if you like it short:

int result = 0;
using (CalculatorServiceClient proxy = new CalculatorServiceClient())
    proxy.BeginAdd(Convert.ToInt32(txtNumber1.Text), Convert.ToInt32(txtNumber2.Text), new AsyncCallback((asyncResult) => {
        result = proxy.EndAdd(asyncResult);
        Dispatcher.Invoke((Action<string>) ((data) => { label1.Content = data; }));
    }), null);

Upvotes: 3

Related Questions