尝试更改后台工作线程中的值单元格
我正在尝试更新后台工作人员中的 Ultragridrow 单元格,但是当调用次数超过 1 次时,会引发 InvalidOperation 异常。
这里有启动 RunWorkerAsync 的方法。
private void RefreshGridCacheStart()
{
try
{
if (this.uGridCache.Rows.Count == 0)
{
return;
}
if(!workerThread.IsBusy)
{
workerThread.DoWork += LookUpHostnames;
workerThread.ProgressChanged += UpdateCacheHostCell;
workerThread.RunWorkerCompleted += WorkerCompleted;
workerThread.WorkerReportsProgress = true;
workerThread.RunWorkerAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
这是 DoWork 方法:
private void LookUpHostnames(object sender, DoWorkEventArgs e)
{
var rowValues = new object[2];
try
{
foreach (UltraGridRow row in uGridCache.Rows)//here is were I get an invalid operation exception
{
string cellValue = row.Cells["Host"].Text;
if (Globals.cNet.isValidIP(cellValue))
{
rowValues[0] = row;
rowValues[1] = cellValue;
workerThread.ReportProgress(0, rowValues);
string resolvedHostname = Globals.cIPLookup.LookupHostFromIP(cellValue);
rowValues[1] = resolvedHostname;
workerThread.ReportProgress(0, rowValues);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
这是 Report Progress 方法:
private void UpdateCacheHostCell(object sender, ProgressChangedEventArgs e)
{
var rowValues = e.UserState as object[];
var row = (UltraGridRow) rowValues[0];
var sMesage = (string) rowValues[1];
row.Cells["Host"].Value = sMesage;
}
I'm trying to update a Ultragridrow cell in a background worker, but this is throwing a InvalidOperation Exception when this is called more than 1 time.
Here you have the method that starts the RunWorkerAsync.
private void RefreshGridCacheStart()
{
try
{
if (this.uGridCache.Rows.Count == 0)
{
return;
}
if(!workerThread.IsBusy)
{
workerThread.DoWork += LookUpHostnames;
workerThread.ProgressChanged += UpdateCacheHostCell;
workerThread.RunWorkerCompleted += WorkerCompleted;
workerThread.WorkerReportsProgress = true;
workerThread.RunWorkerAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
This is the DoWork method:
private void LookUpHostnames(object sender, DoWorkEventArgs e)
{
var rowValues = new object[2];
try
{
foreach (UltraGridRow row in uGridCache.Rows)//here is were I get an invalid operation exception
{
string cellValue = row.Cells["Host"].Text;
if (Globals.cNet.isValidIP(cellValue))
{
rowValues[0] = row;
rowValues[1] = cellValue;
workerThread.ReportProgress(0, rowValues);
string resolvedHostname = Globals.cIPLookup.LookupHostFromIP(cellValue);
rowValues[1] = resolvedHostname;
workerThread.ReportProgress(0, rowValues);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + "\n" + ex.Source + "\n" + ex.ToString());
}
}
And this is the Report Progress method:
private void UpdateCacheHostCell(object sender, ProgressChangedEventArgs e)
{
var rowValues = e.UserState as object[];
var row = (UltraGridRow) rowValues[0];
var sMesage = (string) rowValues[1];
row.Cells["Host"].Value = sMesage;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以找到答案 这里 不同的问题,但最终是相同的问题。您正在 foreach 循环内更改数据,这会使枚举器无效。
通过阅读您的代码,我看到了两种可能的解决方案
You can find your answer here Different question but ultimately the same problem. Your are changing data inside a foreach loop which invalidates the enumerator.
There are 2 possible solutions I see from reading your code
听起来好像某些东西必须更改底层行集合,从而使您的可枚举无效。
如果您使用
.ToList()
将枚举转换为列表(这将导致枚举迭代并为您提供一个包含原始列表中的项目的新列表),您将能够迭代这个新列表可枚举并且源中的更改不会影响您。您必须注意,如果其他内容正在更改网格上的行,您的 ReportProgress 可能会报告网格中不再存在的某些内容的进度,您可能需要在 ReportProgress 处理程序中检查是否报告该项目的进度在做任何事情之前仍然有效。
Sounds like something must be changing the underlying row collection hence invalidating your enumerable.
If you convert your enumerable to a list using
.ToList()
(this will cause the enumerable to iterate and give you a new list containing the items in the original) you will be able to iterate over this new enumerable and changes in the source won't affect you.You will have to be aware that if something else is changing the rows on the grid, your ReportProgress might be reporting progress of something that no longer exists in the grid, you might want to check in your ReportProgress handler whether reporting on progress for that item is still valid before doing whatever you do.
DoWork 上的 MSDN 文档声明如下:
“您必须小心,不要在 DoWork 事件处理程序中操作任何用户界面对象。而是通过 BackgroundWorker 事件与用户界面进行通信。”。
您可以在此处查看 DoWork 方法的完整详细信息:
http://msdn.microsoft.com/en-us /library/system.componentmodel.backgroundworker.dowork.aspx
从此事件访问 UltraGridRows 会导致您从另一个线程访问 UltraGrid,并且 Windows 窗体控件不是线程安全的。
请注意,这并不限于访问控件的属性。如果您要在 UltraGrid 绑定到的数据源中设置值,则会遇到相同的问题,因为更改通知将在后台线程上发生,并且 UI 仍将从后台线程进行操作。
请注意,只有少数成员在 Windows 窗体控件上实际上是线程安全的,这些成员记录在 MSDN 上的控件线程安全部分中: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.aspx
安全、简单Windows 窗体中的多线程是 Windows 窗体中线程处理的一个很好的资源,尽管它较旧:
如何:对 Windows 窗体控件进行线程安全调用 也是一个很好的资源
http://msdn.microsoft.com/en-us/library/ms171728.aspx
The MSDN documentation on DoWork states the following:
"You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the BackgroundWorker events.".
You can view the full details of the DoWork method here:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx
Accessing the UltraGridRows from this event is causing you to access the UltraGrid from another thread and windows forms controls aren't thread safe.
Note that this isn't limited to accessing properties of the control. If you were to set values in the data source that the UltraGrid is bound to you would have the same issue as the change notifications would then happen on the background thread and the UI would still be manipulated from the background thread.
Note that there are only a few members that are actually thread safe on windows forms controls and these are documented in the section on Thread Safety for Control on MSDN: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.aspx
Safe, Simple Multithreading in Windows Forms is a good resource for threading in windows forms even though it is older:
How to: Make Thread-Safe Calls to Windows Forms Controls is also a good resource
http://msdn.microsoft.com/en-us/library/ms171728.aspx