1

あるメンバーで「クロススレッド操作が無効」になりましたが、別のメンバーではなく、両方が同じフォーム、同じ UI スレッドに属していると思います。それらのメンバーはuxServerGroupuxServerListenです。テキストを変更するuxServerGroup.ValuesSecondary.Headingと正常に動作し、クロススレッド例外は発生しません。uxServerListenしかし、ボタンを有効にしようとすると、1つ取得されます。なぜですか?

これらのコンポーネントはどちらも 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);
        }
    }
}

ClassHandler.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 に答える