问题
the following code is used to trigger invoke (code is reduced, i left out the error handling in this example to make it more clear)
public static void InvokeIfNecessary(this Control control, MethodInvoker methodInvoker)
{
if (control != null && !control.IsDisposed && !control.Disposing)
{
if (control.InvokeRequired)
{
control.Invoke(methodInvoker);
}
else
{
methodInvoker();
}
}
}
Normally it works fine, but sometimes if i call a method of a Form an InvalidOperationException is given. Schematic method to be called
// in a Frm2:
internal void UpdateSomething()
{
List<NO> myObjects = frmMain.NO.GetNOs();
if (null != myObjects)
{
this.InvokeIfNecessary(() =>
{
layoutControlGroup.BeginUpdate(); // DevExpress Layoutcontrolgroup
foreach (NO aObject in myObjects)
{
if(...) // if already a control for the object exist update it.
{
// update
}
else
{
// add item
LayoutControlItem layoutControlItem = new LayoutControlItem();
// create new control
Control control = CreateNewControl(aObject);
layoutControlItem.Control = control;
// do some stuff with visibility and size of control
...
layoutControlGroup.AddItem(layoutControlItem); // <-- And here the InvalidOperationException occurs.
/// The message is (translated
/// InvalidOperationException was not handled by usercode
/// The acces on the Control FrmMain was done from another Thrad then the thread which created it.
...;
}
}
...;
layoutControlGroupCA.EndUpdate();
});
}
}
Well... I must admit that i have a conceptual problem here.
Why is the Exception thrown here?
The Frm2 method creates a new element (In NO there is only a string and a struct with strings and bool). The element is only accessed within the UpdateSomething() method. The layOutControlGroup is a member of Frm2.
So in my opinion only a new Control which shoudl be created in Frm2 Thread should be attached to a Frm2 specific Control.
So why does it insisting in FrmMain? (the main form, which calls the method of the form to inform about an update of items)
P.S. this.InvokeIfRequired <- this is Frm2 actually...
回答1:
So, as we see, there are always trouble with ( begin) invoke. Use BeginInvoke instead. is my hint. Usually it says, that begin invoke on controls executes a method in the same thread where the handle was created on.
But as it seems, the handle of form2 is not been created in the same thread, OR perhaps it is not present yet. Try to check this and verify this, please.
Ah. by the way, flag exceptions, clr, in visual studio, when they are thrown. This helps to spot the error.
回答2:
I think that you checked InvokeRequired
with a wrong control.
What you needed to check with InvokeRequired
is layoutControlGroup
, but your extension method checks on form's with the code this.InvokeIfNecessary
where this
is Frm2.
Also, you invoked layoutControlGroup.BeginUpdate()
but layoutControlGroupCA.EndUpdate()
, seems not symmetric of the usage.
A correction of the code might be:
internal void UpdateSomething() {
var myObjects=frmMain.NO.GetNOs();
if(null!=myObjects) {
MethodInvoker beginUpdate=() => layoutControlGroup.BeginUpdate();
MethodInvoker endUpdate=() => layoutControlGroup.EndUpdate();
layoutControlGroup.InvokeIfNecessary(beginUpdate);
foreach(NO aObject in myObjects)
if(SomeCondition) {
// update
}
else {
LayoutControlItem layoutControlItem=new LayoutControlItem();
Control control=CreateNewControl(aObject);
layoutControlItem.Control=control;
MethodInvoker addItem=
() => {
layoutControlGroup.AddItem(layoutControlItem);
};
layoutControlGroup.InvokeIfNecessary(addItem);
}
layoutControlGroup.InvokeIfNecessary(endUpdate);
}
}
来源:https://stackoverflow.com/questions/16961404/invalideoperationexception-invoke