C#,WPF,在没有backgroundworkers的情况下更新gui

时间:2010-02-04 15:15:40

标签: c# wpf

我有一个程序需要10-20秒才能启动。我需要在程序启动时显示一个带有进度条的窗口。我知道BackgroundWorker是正确的方法,但我很遗憾没有时间使用线程重做整个gui。这是我正在尝试的一些代码,但它不起作用。谁能帮忙..?

using System;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            Thread t = new Thread(ShowLoadingWindow);
            t.SetApartmentState(ApartmentState.STA);
            t.Priority = ThreadPriority.Highest;
            t.Start();

            DoSomeLongTask();
            keepLooping = false;
        }

        bool keepLooping = true;
        private void ShowLoadingWindow()
        {
            LoadingWindow lw = new LoadingWindow();
            lw.Show();

            while (keepLooping)
            {
                Thread.Sleep(1);
            }

            lw.Close();
        }

        private void DoSomeLongTask()
        {
            for (int i = 0; i < 20000; i++)
            {
                GC.Collect();
            }
        }
    }
}

加载窗口只是一个带有进度条的裸窗口。如果这不起作用?

3 个答案:

答案 0 :(得分:10)

你仍然在主线程中完成长任务。您需要在主线程中显示加载窗口,并在后台执行长任务

使用BackgroundWorker确实是最简单的解决方案:

BackgroundWorker bw;
LoadingWindow lw;

public Window1() {
    bw = new BackgroundWorker();
    lw = new LoadingWindow();

    bw.DoWork += (sender, args) => {
        // do your lengthy stuff here -- this will happen in a separate thread
        ...
    }

    bw.RunWorkerCompleted += (sender, args) => {
        if (args.Error != null)  // if an exception occurred during DoWork,
            MessageBox.Show(args.Error.ToString());  // do your error handling here

        // close your loading window here
        ...
    }

    // open and show your loading window here
    ...

    bw.RunWorkerAsync(); // starts the background worker
}

答案 1 :(得分:5)

使用backgroundworker非常容易。

public partial class Window1 : Window
{
    BackgroundWorker worker = new BackgroundWorker();

    public Window1()
    {
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.ReportsProgress = true;
        worker.ProgressChanged += new ProgressChangedEventHandler(update_progress);
    }


    void worker_DoWork(object sender, DoWorkEventArgs e){
        DoSomeLongTask();
        //call worker.ReportProgress to update bar
    }

    void update_progress(object sender, ProgressChangedEventArgs e)
    {
        myscrollbar.Value = e.Value;
    }
}

要记住的关键是永远不要触摸DoWork方法中的gui东西。这必须通过ProgressChanged / ReportProgress

答案 2 :(得分:3)

如果您不想要后台工作程序,则需要调整代码,以便在新线程中执行长任务。

using System;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
      public Window1()
      {
          InitializeComponent();

          Thread t = new Thread(DoSomeLongTask);
          t.Start();

          // switch this with the DoSomeLongTask, so the long task is
          // on the new thread and the UI thread is free.
          ShowLoadingWindow();
    }
  }
}

如果您想从“DoSomeLongTask”方法更新进度条,则需要确保调用invoke。例如:

delegate void ProgressDelegate(int Progress);  
private void UpdateProgress( int  Progress)  
{  
   if (!progressBar1.Dispatcher.CheckAccess())  
   {  
     progressBar1.Value = Progress;  
   }  
   else  
   {  
     ProgressDelegate progressD = new ProgressDelegate(UpdateProgress);  
     progressBar1.Dispatcher.Invoke(progressD, new object[] { Progress });  
   }  
}