WPF多线程进度对话框

更新这是我遇到的一个有趣的问题。 当后台进程运行时,我需要进行进度对话框显示。 通常情况下,这将工作,但问题是我需要在后台进程中设置公共静态数据。 以下是我试图完成的一个例子:

public partial class MainWindow : Window
{
    public static Service binding;
    public static Result lr;
    public progressDialog dlg;

    private void login()
    {
        string sPwd = txtPwd.Password;
        string sEmail = txtEmail.Text;
        binding = new Service();
        lr = binding.login(sEmail, sPwd);
    }
    private void btnLogin_Click(object sender, RoutedEventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker;
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted)
        worker.RunWorkerAsync();
        dlg = new progressDialog();
        dlg.Show();
        login();
    }
    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        e.Result = login();
    }
    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.Hid();
        Window1 newWindow = new Window1();
        newWindow.Show();
        dlg.Close();
    }

我知道,因为这是站立的,它不会工作,因为login()是一个void,并且实际上并没有返回一个值用于DoWork事件中的e.Result。 但是,我设置了一个登录类来传递参数,并且仍然收到错误,指出我无法访问UI线程。 主要的问题是,lr和绑定被另一个窗口访问,所以它们必须是公共静态数据(从另一个窗口我设置公共静态服务绑定= MainWindow.binding;)。 我只是在围绕如何设置它的过程中遇到一些麻烦。


您需要在前台线程上读取TextBoxes(txtEmail和txtPwd),而不是后台线程。 这是一个例子:

class MainWindow
{
  private string _email;
  private string _password;

  private void btnLogin_Click(...)
  {
    // running on UI thread here - can touch text boxes
    _email = txtEmail.Text;
    _password = txtPwd.Text;
    // ... set up worker ...
    worker.RunWorkerAsync();
  }

  private void login()
  {
    binding = new Service();
    // running on background thread here
    // but safe to access _email and _password they're just data, not UI controls
    lr = binding.login(_email, _password);
  }
}

编辑:甚至更好,传递电子邮件和密码作为参数,而不是将它们存储在成员变量中:

  private void btnLogin_Click(...)
  {
    // running on UI thread here - can touch text boxes
    LoginInfo loginInfo = new LoginInfo(txtEmail.Text, txtPwd.Text);
    // ... set up worker ...
    worker.RunWorkerAsync(loginInfo);  // note argument
  }

  private void worker_DoWork(...)
  {
    LoginInfo loginInfo = (LoginInfo)(e.Argument);
    // now pass the LoginInfo to login() as an argument
  }

(并删除_email和_password成员)


你正在考虑这个错误的方式。

你需要在主线程上显示你的进度对话框,否则你的后台工作人员不会。

然后,在BackgroundWorker.DoWork处理程序中,执行您的实际工作。 这在后台线程中运行。

定期在工作进展期间,调用BackgroundWorker.ReportProgress。 这将在UI线程中将进度推到一个平台上。

您需要订阅BW.ProgressChanged事件,并且您将在此处更新progressDialog中的进度条。 这发生在UI线程上自动。

您的工作以及对ReportProgress的调用只需成为DoWork事件处理程序中的唯一事物即可。


要访问在非UI线程中引发的事件中调用的事件处理程序中的UI元素,您需要如下代码所示的内容:

Action action = () => FinalUpdate();
if (Thread.CurrentThread != Dispatcher.Thread)
{
    Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, action);
}
else
{
    action();
}

如果可以,请通过Bill Wagner掌握更有效的C#的副本。 他有关于多线程和后台工作线程的全部内容。

链接地址: http://www.djcxy.com/p/46565.html

上一篇: WPF multithreaded progress dialog

下一篇: Add Generic list in a MyClass but how?