8

SolidColorBrush非 GUI スレッドでを作成し、それを GUI スレッドに渡して表示したいのですが、取得しようとしてもInvalidOperationException:になります。スレッド X で作成されたオブジェクトをスレッド Y に渡すにはどうすればよいですか?The calling thread cannot access this object because a different thread owns it.Freeze();

このSolidColorBrushオブジェクトを GUI スレッドDispatcher


追加の詳細:

ビジネス層から GUI にメッセージを送信できるように、いくつかの静的クラスでいくつかの静的デリゲートを初期化します。

public static class Gui{
    private static PrintMethodDelegate _printMethod;
    public static void InitializeGuiInterface(PrintMethodDelegate printMethod){
        _printMethod = printMethod;
    }
    public static void Print(GuiMessage data) { _printMethod(data); }
}

初期化 (GUI スレッドで):

Gui.InitializeGuiInterface(_messagesToUserHandler.PrintMessage);

次に、別の (GUI 以外の) スレッドで、それを使用します。

Gui.Print(new GuiMessage(testDescription) { Foreground = new SolidColorBrush(someColor) });

一方GuiMessageは:

public class GuiMessage {
    public string Msg { get; set; }

    private SolidColorBrush _foregroundBrush;
    public SolidColorBrush Foreground
    {
        get { return _foregroundBrush; }
        set { _foregroundBrush = value; }
    }
}
4

3 に答える 3

8

それらをフリーズすると、別のスレッドで wpf リソースを作成できます。その後、要素をさらに別のスレッドまたは gui スレッドに渡すことができます。一度凍結されたオブジェクトは、コピーを作成してそのコピーを使用することによってのみ変更できることに注意してください。バインディングまたはアニメーションがアタッチされているオブジェクトをフリーズすることはできません。

于 2013-05-06T11:51:47.890 に答える
0

Dispatcherを使用する必要があります。

メイン スレッドで作成されたディスパッチャを保持するクラスを作成し、コンテナを介して、メイン スレッドと対話する必要があるバックグラウンド スレッドで実行される任意のクラスに注入できます。

public interface IUiDispatcher
{
    Dispatcher Dispatcher { get; }
}

public class UiDispatcher : IUiDispatcher
{
    public UiDispatcher()
    {
        if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA
            && !Thread.CurrentThread.IsBackground
            && !Thread.CurrentThread.IsThreadPoolThread)
        {
            this.Dispatcher = Dispatcher.CurrentDispatcher;
        }
        else
        {
            throw new InvalidOperationException("Ui Dispatcher must be created in UI thread");
        }
    }

    public Dispatcher Dispatcher { get; set; }
}

public class ExecutedOnABackgroundThread
{
    IUiDispatcher uidispatcher;

    public ExecutedOnABackgroundThread(IUiDispatcher uidispatcher)
    {
        this.uidispatcher = uidispatcher;
    }

    public void Method()
    {
        // Do something on the background thread...
        // ...

        // Now we need to do something on the UI
        this.uidispatcher.Dispatcher.BeginInvoke(new Action(delegate
        {
            // Do something
        }), null);
    }
}

UiDispatcherアプリケーションの初期化中など、UI スレッド上にいることが確実な時点でのインスタンスを作成します。依存性注入コンテナーを使用して、このクラスのインスタンスが 1 つだけ作成され、それを必要とする他のクラスに注入され、それを使用して UI コンポーネントを作成/操作するようにします。

この回答UiDispatcherから、コンストラクターがメインスレッドで実行されているかどうかを確認するコードを選択しました。

問題は、別のスレッドで作成されたものを UI スレッドで使用できないことです。そのため、UI スタッフが関与するものは何でもメイン UI スレッドに委任するには、バックグラウンド スレッドが必要です。

于 2013-05-06T07:53:57.903 に答える