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