立即更新UI线程

时间:2013-06-27 20:54:09

标签: c# wpf multithreading

我正在尝试在登录时启用忙碌指示器。我遇到的问题是在完成所有操作后才会启用它。一旦我登录以尽快启动指标,我怎样才能立即告诉线程更新UI?

    private void LoginButton_Click(object sender, RoutedEventArgs e)
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
            radBusyIndicator.IsBusy = true;
            //var backgroundWorker = new System.ComponentModel.BackgroundWorker();
            //backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(backgroundWorker_DoWork);
            //backgroundWorker.RunWorkerAsync();
        }));

        string error = string.Empty;
        long userId = 0;

        //Login code here....
        //...........  bunch of other code. etc..

     }

2 个答案:

答案 0 :(得分:8)

UI线程空闲后,UI将立即更新。在这种情况下,不需要Dispatcher.Invoke,因为您已经在UI线程中。

这里的关键是将“工作”移动到后台线程中,即:

private void LoginButton_Click(object sender, RoutedEventArgs e)
{
    radBusyIndicator.IsBusy = true;
    LoginButton.IsEnabled = false; // Prevent clicking twice

    string error = string.Empty;
    long userId = 0;

    // Start this in the background
    var task = Task.Factory.StartNew(()=>
    {
        //Login code here....
        //...........  bunch of other code. etc..
    });

    // Run, on the UI thread, cleanup code afterwards
    task.ContinueWith(t =>
    {
        // TODO: Handle exceptions by checking t.Exception or similar...

        radBusyIndicator.IsBusy = false;
        LoginButton.IsEnabled = true;
    }, TaskScheduler.FromCurrentSynchronizationContext());
 }

如果您使用的是C#5,则可以通过使登录和其他代码异步来简化此操作:

private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
    radBusyIndicator.IsBusy = true;
    LoginButton.IsEnabled = false; // Prevent clicking twice

    long userId = 0;

    // Call async method with await, etc...
    string error = await DoLoginAsync(userId);

    var result = await BunchOfOtherCodeAsync();

    radBusyIndicator.IsBusy = false;
    LoginButton.IsEnabled = true;
 }

答案 1 :(得分:0)

您可以使用BAckground Worker Thread并将其两个eventHandler添加到您想要处理的事件中。 例如 -

BackgroundWorker Worker=new BackgroundWorker();
worker.DoWork+=Yorevent which will do the timeTaking Task();
Worker.RunWorkerCompleted+=YOurEvent which will Update your UI after the work is done();
worker.RunWorkerAsync();

这样它也不会导致任何线程错误..

启用BusyIndi​​cator作为TimeTaking TAsk启动和timeTaking任务完成时只需在RUnWorkerCompleted事件中禁用忙碌指示器。