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
我希望我帮忙