Jus*_*tin 14 .net c# multithreading winforms
我是多线程的新手.我有一个带有标签和进度条的winform.
我想显示处理结果.首先,我使用Application.DoEvents()方法.但是,我发现表格很冷.
然后我在MSDN上阅读了一些关于多线程的文章.
其次,我使用BackgroundWorker来做到这一点.
this.bwForm.DoWork += (o, arg) => { DoConvert(); };
this.bwForm.RunWorkerAsync();
Run Code Online (Sandbox Code Playgroud)
表格不会冻结,我可以在处理时拖动/ drog.不幸的是,它会抛出InvalidOperationException.所以我必须使用它.Control.CheckForIllegalCrossThreadCalls = false;我确保这不是最终的解决方案.
专家,您有什么建议吗?
编辑: 当我调用listview时抛出InvalidOperationException.此代码位于DoWork()中.
foreach (ListViewItem item in this.listView1.Items)
{
//........some operation
lbFilesCount.Text = string.Format("{0} files", listView1.Items.Count);
progressBar1.Value++;
}
Run Code Online (Sandbox Code Playgroud)
Edit2: 我在DoWork()中使用委托并调用它并不会抛出异常.但形式再次冻结.怎么做才能使表格在处理时可以放置/悬垂?
调用UI线程.例如:
void SetControlText(Control control, string text)
{
if (control.InvokeRequired)
control.Invoke(SetControlText(control, text));
else
control.Text = text;
}
Run Code Online (Sandbox Code Playgroud)
您只能从UI线程(WinForm)设置进度条用户控件属性.使用BackgroundWorker最简单的方法是使用ProgressChanged事件:
private BackgroundWorker bwForm;
private ProgressBar progressBar;
Run Code Online (Sandbox Code Playgroud)
在WinForm构造函数中:
this.progressBar = new ProgressBar();
this.progressBar.Maximum = 100;
this.bwForm = new BackgroundWorker();
this.bwForm.DoWork += new DoWorkEventHandler(this.BwForm_DoWork);
this.bwForm.ProgressChanged += new ProgressChangedEventHandler(this.BwForm_ProgressChanged);
this.bwForm.RunWorkerAsync();
Run Code Online (Sandbox Code Playgroud)
...
void BwForm_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bgw = sender as BackgroundWorker;
// Your DoConvert code here
// ...
int percent = 0;
bgw.ReportProgress(percent);
// ...
}
void BwForm_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar.Value = e.ProgressPercentage;
}
Run Code Online (Sandbox Code Playgroud)
请看:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
编辑
所以我不明白你的问题,我认为这是关于在工作期间显示进度条的进展.如果是关于工作的结果,请在BwForm_DoWork事件中使用e.Result.为已完成的事件添加新的事件处理程序并管理结果:
this.bwForm.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.BwForm_RunWorkerCompleted);
Run Code Online (Sandbox Code Playgroud)
...
private void BwForm_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
YourResultStruct result = e.Result as YourResultStruct;
if (e.Error != null && result != null)
{
// Handle result here
}
}
Run Code Online (Sandbox Code Playgroud)
避免打电话Application.DoEvents.通常情况下,这会导致比解决的问题更多的问题.它通常被认为是不好的做法,因为存在更好的替代方案,以保持UI抽取消息.
避免改变设置CheckForIllegalCrossThreadCalls = false.这不能解决任何问题.它只掩盖了问题.问题是您正在尝试从主UI线程以外的线程访问UI元素.如果你禁用,CheckForIllegalCrossThreadCalls那么你将不再获得异常,而是你的应用程序将无法预测和惊人地失败.
在DoWork事件处理程序中,您需要定期调用ReportProgress.从您Form那里您将要订阅该ProgressChanged活动.从ProgressChanged事件处理程序中访问UI元素是安全的,因为它会自动封送到UI线程中.
最干净的方式是BackGroundWorker像你一样使用.
你错过了一些观点:
DoWork事件处理程序中访问表单元素,因为这会使跨线程方法调用,这应该在ProgressChanged事件处理程序中完成.BackGroundWorker不允许报告进度,也不允许取消操作.当您添加BackGroundWorker到您的代码,你必须设置WorkerReportsProgress的那个属性BackGroundWorker来true,如果你想打电话给ReportProgress你的方法BackGroundWorker.WorkerSupportsCancellation为true并在DoWork事件处理程序的循环中检查CancellationPending您的名称中指定的属性BackGroundWorker我希望我帮忙