0

WPFViewModelの次のコードを検討してください。

protected void Init()
{
    Debug.WriteLine(string.Format("ChangeManager init on thread={0}", Thread.CurrentThread.ManagedThreadId));          

    var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

    this.modelChanged = (o, args) => Task.Factory.StartNew(() =>
        {                   
            Debug.WriteLine(string.Format("ModelChanged on thread={0}", Thread.CurrentThread.ManagedThreadId));
            this.ModelChanged(o, args);
        },
        CancellationToken.None,
        TaskCreationOptions.None,
        uiTaskScheduler);
}

...ここで、modelChangedは、オブジェクトモデルの変更に応答するためのイベントハンドラーです。このコードはUIスレッドで実行され、発生元のスレッドに関係なく、UIスレッドでイベントが処理されることを期待して設計されています。

ただし、これを実行すると、出力は次のようになります。

ChangeManager init on thread=1
ModelChanged on thread=3
ModelChanged on thread=3
ModelChanged on thread=7
ModelChanged on thread=9

私の期待は、スレッド1がすべての処理が行われる場所になることです。このようにSynchronizationContextを直接使用しようとしても:

protected void Init()
{
    Debug.WriteLine(string.Format("ChangeManager init on thread={0}", Thread.CurrentThread.ManagedThreadId));          

    this.uiContext = SynchronizationContext.Current;        

    modelChanged = (o, args) => uiContext.Post((ignore) => {
        Debug.WriteLine(string.Format("ModelChanged on thread={0}", Thread.CurrentThread.ManagedThreadId));
        this.ModelChanged(o, args);
    }
    , null);
}

...同じことがわかります。

私の考え方やアプローチに何か問題がありますか?initスレッドでイベントを処理するにはどうすればよいですか?

前もって感謝します!

4

2 に答える 2

2

興味深いことに、あなたのコードは私のために機能します。問題を説明できるコードの一部を省略した可能性があります。問題のより完全な再現を投稿できますか? modelChanged具体的には、ラムダをメンバーに割り当てる以外に、メンバーで何をしているのかを示します。

私がしたことは、空の WPF アプリケーションを作成し、メイン ウィンドウのコンストラクターから Init メソッドを実行することでした。

modelChanged次に、デリゲートを直接呼び出すバックグラウンド スレッドを開始しました。

私が見たのは、「ModelChanged on thread...」という行が常に正しいスレッド、つまりInit.

それが助けになる場合は、これを再現するために私が行ったことを次に示します。それを見て、別の方法で行っていることについて投稿してください。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Init();
    }

    private EventHandler modelChanged;

    protected void Init()
    {
        Trace.WriteLine(string.Format("ChangeManager init on thread={0}",
                 Thread.CurrentThread.ManagedThreadId));

        var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

        modelChanged = (o, args) => Task.Factory.StartNew(() =>
        {
            Trace.WriteLine(string.Format("ModelChanged on thread={0}", 
                Thread.CurrentThread.ManagedThreadId));

            if (ModelChanged != null)
            {
                ModelChanged(o, args);
            }
        },
            CancellationToken.None,
            TaskCreationOptions.None,
            uiTaskScheduler);
    }

    public event EventHandler ModelChanged;

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        var t = new Thread(
            obj =>
                 {
                      Trace.WriteLine(string.Format(
                          "Launching handler on thread={0}", 
                          Thread.CurrentThread.ManagedThreadId));

                      modelChanged(null, EventArgs.Empty);
                 });
        t.Start();
    }
}
于 2011-10-18T22:21:01.633 に答える