有没有更好的方法来使用Dispatcher更新UI元素?

时间:2009-07-18 17:05:33

标签: wpf wcf asynchronous dispatcher

我是WCF服务的新手,我正在试图弄清楚当我异步调用我的WCF服务时是否有更好的方法来更新WPF UI元素(比如Label控件)。

这是一段代码:

    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);

    }

正如您所看到的,我正在使用AsyncCallback获取的异步结果更新label1.Content。

我的问题是,是否有更好或更正确的方法来刷新此异步回调操作中的UI控件?

提前感谢!

2 个答案:

答案 0 :(得分:3)

Dispatcher.Invoke是更新UI的好方法。 UI操作必须由UI线程执行,Dispatcher负责处理此事。

使用Lambda表达式可以缩短代码:

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

我还建议将代理放在Using语句中,这样就可以了:

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);
}

或者如果你喜欢简短:

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);

答案 1 :(得分:1)

可以做得更短:

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);
}

诀窍是,Invoke / BeginInvoke并不意味着你必须显式传递参数,编译器无论如何都要运行它。

你不想使用Invoke,因为它不需要后台线程。