1

我在一个成员中得到一个“无效的跨线程操作”,但在另一个成员中却没有,它们都属于同一个表单,我相信是同一个 UI 线程。这些成员是uxServerGroupuxServerListen。当我更改它上面的文本时,uxServerGroup.ValuesSecondary.Heading它工作正常,我没有得到一个跨线程异常。但是当我尝试启用uxServerListen按钮时,我确实得到了一个。为什么

我可能应该注意到,这两个组件都属于 Krypton Toolkit,它们不是标准的 Windows 窗体。

这是我拥有的代码示例:

MainForm.cs:

public partial class MainForm : Form {
    public MainForm() {
        InitializeComponent();
        SomeClass.ObjectStateChanged += new ObjectStateEventHandler(SomeClass_ObjectStateChanged);
    }

    private void uxServerListen_Click(object sender, EventArgs e) {
        uxServerListen.Enabled = false;

        ClassHandler ch = ClassHandler();
        ch.Initialize();
    }

    private void SomeClass_ObjectStateChanged(Enum e1, Enum e2) {
        switch(e1) {
            case E1.TypeA:
                HandleTypeAObjectChanges(e1);
                break;
            case E1.TypeB:
                HandleTypeBObjectChanges(e2);
                break;
        }
    }

    private void HandleTypeAObjectChanges(Enum e2) {
        switch(e2) {
            case E2.ModeA:
                uxServerGroup.ValuesSecondary.Image = Resources.StatusSuccess16;
                break;
            case E2.ModeB:
                uxServerGroup.ValuesSecondary.Image = Resources.StatusFailure16;
                uxServerListen.Enabled = true;
                break;
        }
    }
}

SomeClass.cs:

public delegate void ObjectStateEventHandler(Enum e1, Enum e2);

public static class SomeClass {
    public static event ObjectStateEventHandler ObjectStateChanged;

    internal static E1 e1;

    internal static void ObjectStateChanged(Enum e2) {
        if(ConnectionStateChanged != null) {
            ConnectionStateChanged(e1, e2);
        }
    }
}

类处理程序.cs:

public class ClassHandler {
    public ClassHandler() {
        // (...)
    }

    public void Initialize() {
        Thread thread = new Thread(new ThreadStart(SomeMethod));
        thread.Start();
    }

    private void SomeMethod() {
        SomeClass.ObjectStateChanged(E2.ModeB);
    }
}

经过大量搜索,我最终将其修复为:

private void SomeClass_ObjectStateChanged(Enum e1, Enum e2) {
        if(InvokeRequired) {
            Invoke(new MethodInvoker(() => {
                switch(e1) {
                    case E1.TypeA:
                        HandleTypeAObjectChanges(e2);
                        break;
                    case E1.TypeB:
                        HandleTypeBObjectChanges(e2);
                        break;
                }
            }));
        }
    }

作为一个额外的问题,有人可以解释一下(里面的东西MethodInvoker):

new MethodInvoker(() => { /* (...) */ })
4

1 回答 1

1

我在一个成员中得到“跨线程操作无效”,但在另一个成员中没有

需要专门检测无效的跨线程操作来触发可用异常。如果没有检测到,您将不会得到该异常。但请注意:不要将其视为从另一个线程访问属性的权限,通常仍然不允许这样做,并且少数例外将被记录为线程安全的。

作为一个额外的问题,有人可以解释一下(MethodInvoker里面的东西):

new MethodInvoker(() => { /* (...) */ })

这将创建一个匿名内联方法,当调用时,/* (...) */语句将被执行。然后创建Adelegate以使该方法可调用,这就是传递给Invoke. 通常,像这样稍微更精细地编写它会更容易:

MethodInvoker foo = () =>
{
    ...
};
// no part of the ... above has run yet
if (!control.InvokeRequired)
    foo(); // call foo directly
else
    control.Invoke(foo); // let the UI thread call foo
于 2012-03-19T23:33:03.900 回答