WPF 多线程进度对话框 [英] WPF multithreaded progress dialog

查看:31
本文介绍了WPF 多线程进度对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新这是我遇到的一个有趣的问题.我需要在后台进程运行时显示进度对话框.通常,这会起作用,但问题是我需要在后台进程中设置公共静态数据.这是我试图完成的一个示例:

<上一页>公共部分类 MainWindow : 窗口{公共静态服务绑定;公共静态结果 lr;公共进度对话框 dlg;私人无效登录(){字符串 sPwd = txtPwd.密码;字符串 sEmail = txtEmail.Text;绑定=新服务();lr = binding.login(sEmail, sPwd);}私人无效btnLogin_Click(对象发送者,RoutedEventArgs e){BackgroundWorker 工作者 = 新的 BackgroundWorker;worker.DoWork += new DoWorkEventHandler(worker_DoWork);worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted)worker.RunWorkerAsync();dlg = 新进度对话框();dlg.Show();登录();}private void worker_DoWork(object sender, DoWorkEventArgs e){e.Result = login();}私人无效工人_RunWorkerCompleted(对象发送者,RunWorkerCompletedEventArgs e){this.Hid();窗口 1 新窗口 = 新窗口 1();新窗口.Show();dlg.关闭();}

我知道就目前而言,它不会起作用,因为 login() 是一个 void 并且实际上并没有返回一个值以在 DoWork 事件中与 e.Result 一起使用.但是,我已经设置了一个登录类来传递参数,但我仍然收到错误消息,指出我无法访问 UI 线程.主要问题是 lr 和 binding 由另一个窗口访问,因此它们必须是公共静态数据(从另一个窗口我设置 public static Service binding = MainWindow.binding;).我只是在思考如何设置它时遇到了一些麻烦.

解决方案

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

类 MainWindow{私人字符串_email;私人字符串_密码;私人无效 btnLogin_Click(...){//在 UI 线程上运行 - 可以触摸文本框_email = txtEmail.Text;_password = txtPwd.Text;//... 设置工作者 ...worker.RunWorkerAsync();}私人无效登录(){绑定=新服务();//这里在后台线程上运行//但可以安全地访问 _email 和 _password 它们只是数据,而不是 UI 控件lr = binding.login(_email, _password);}}

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

 private void btnLogin_Click(...){//在 UI 线程上运行 - 可以触摸文本框LoginInfo loginInfo = new LoginInfo(txtEmail.Text, txtPwd.Text);//... 设置工作者 ...worker.RunWorkerAsync(loginInfo);//注意参数}私人无效工人DoWork(...){LoginInfo loginInfo = (LoginInfo)(e.Argument);//现在将 LoginInfo 作为参数传递给 login()}

(并删除 _email 和 _password 成员)

Updated This is kind of an interesting problem I am experiencing. I need to have a progress dialog show when a background process is running. Normally, this would work but the problem is that I need to set public static data within the background process. Here is an example of what I am attempting to accomplish:

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

I know that as this stands, it will not work because login() is a void and does not actually return a value to use with e.Result in the DoWork event. However, I have set up a login class to pass the parameters to and I still receive errors stating that I cannot access the UI thread. The main problem is that lr and binding are accessed by another window so they must be public static data (from the other window I set public static Service binding = MainWindow.binding;). I'm just having a bit of trouble wrapping my head around how exactly to set this up.

解决方案

You need to read from the TextBoxes (txtEmail and txtPwd) on the foreground thread, not the background thread. Here's an example:

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

EDIT: Even better, pass the email and password as arguments rather than storing them in member variables:

  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
  }

(and remove the _email and _password members)

这篇关于WPF 多线程进度对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆