我正在使用backgroundWorker
进行长时间运行:
BackgroundWorker backgroundWorker = new BackgroundWorker() { WorkerSupportsCancellation = true, WorkerReportsProgress = true };
backgroundWorker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
};
backgroundWorker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
someViewModel.SomeProperty.Add((SomeObject)args.UserState);
};
backgroundWorker.DoWork += delegate(object s, DoWorkEventArgs args)
{
someViewModel.SomeList.ForEach(x =>
{
someViewModel.SomeInterface.SomeMethod(backgroundWorker, someViewModel, someViewModel.SomeList, x);
});
};
backgroundWorker.RunWorkerAsync();
然后在SomeInterface.SomeMethod
:
public void SomeMethod(BackgroundWorker backgroundWorker, SomeViewModel someViewModel//....)
{
//Filtering happens
backgroundWorker.ReportProgress(0, someObjectFoundWhileFiltering);
}
所以,当涉及到:
backgroundWorker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
someViewModel.SomeProperty.Add((SomeObject)args.UserState);//Adding the found object to the Property in the VM
};
在someViewModel.SomeProperty.Add((SomeObject)args.UserState);
行上,SomeProperty
上的设置不会发送,而UI
只会锁定。
我做错了什么?这是更新UI thread
答案 0 :(得分:0)
我希望您正在开发一个Windows窗体应用程序,然后如果您正在使用委托更新或向表单组件发送一些值,请将您的请求放入主线程Q,尝试通过这种方式你可以找到解决方案。
答案 1 :(得分:0)
对winforms控件的跨线程调用很危险。它们可能导致不可预测的结果。 有时您会遇到特殊例外。有时UI不会被重新绘制......在你的情况下,你会被挂起。
为避免这种情况,请调用此处http://msdn.microsoft.com/en-us/library/ms171728.aspx中所述的UI。 像这样:
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
请注意,此元文本必须放入UI上下文中,因此此指的是来自或控制。 调用将请求放入UI消息队列,然后通过在UI线程中运行的UI消息循环进行提取和处理。
答案 2 :(得分:0)
现在找到一个解决方法:
DeepClone object
。
backgroundWorker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
ViewModel.SomeList = DeepClone<List<SomeObject>>(ViewModel.TempList);
};
backgroundWorker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
var item = DeepClone<SomeObject>((SomeObject)args.UserState);
ViewModel.TempList.Add(item);
};
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}