1

以下代码用于触发调用(代码减少,我在此示例中省略了错误处理以使其更清晰)

public static void InvokeIfNecessary(this Control control, MethodInvoker methodInvoker)
{
    if (control != null && !control.IsDisposed && !control.Disposing)
    {

        if (control.InvokeRequired)
        {
            control.Invoke(methodInvoker);
        }
        else
        {
            methodInvoker();
        }
    }
}

通常它工作正常,但有时如果我调用 Form 的方法,则会给出 InvalidOperationException。要调用的示意方法

// 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();
        });
    }
}

嗯......我必须承认我在这里有一个概念问题。

为什么这里会抛出异常?

Frm2 方法创建一个新元素(在 NO 中只有一个字符串和一个带有字符串和布尔值的结构)。该元素只能在 UpdateSomething() 方法中访问。layoutControlGroup 是 Frm2 的成员。

所以在我看来,只有应该在 Frm2 线程中创建的新控件应该附加到 Frm2 特定控件。

那么它为什么坚持在 FrmMain 中呢?(主窗体,它调用窗体的方法来通知项目的更新)

PS this.InvokeIfRequired <- 这实际上是 Frm2 ......

4

2 回答 2

0

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);
    }
}
于 2013-06-06T12:32:03.910 回答
0

所以,正如我们所见,(begin) 调用总是有问题的。请改用 BeginInvoke。是我的提示。通常它说,控件上的开始调用在创建句柄的同一线程中执行一个方法。

但看起来,form2 的句柄不是在同一个线程中创建的,或者它可能还不存在。请尝试检查并验证这一点。

啊。顺便说一句,当异常被抛出时,在 Visual Studio 中标记异常 clr。这有助于发现错误。

于 2013-06-06T12:03:45.293 回答