10

.NET、Windows 8、および Windows Phone 7 には、次のようなコードがあります。

public static void InvokeIfRequired(this Dispatcher dispatcher, Action action)
{
    if (dispatcher.CheckAccess())
    {
        action();
    }
    else
    {
        dispatcher.Invoke(action);
    }
}

ポータブル クラス ライブラリで何かを行うにはどうすればよいですか? プラットフォームにとらわれない実装が 1 つあると便利です。私の考えは、WP7 では利用できない TPL を使用することですが、間違いなくすぐに利用できるようになるでしょう。

// PortableDispatcher must be created on the UI thread and then made accessible 
// maybe as a property in my ViewModel base class.
public class PortableDispatcher
{
    private TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

    public void Invoke(Action action)
    {
        if (Alread on UI thread. How would I do this.)
        {
            action();
        }

        Task.Factory.StartNew(
            action, 
            CancellationToken.None,
            TaskCreationOptions.None,
            taskScheduler);
    }
}

私が確信していない唯一のことは、これがパフォーマンスにどのような影響を与えるかです。おそらく私はいくつかのテストを行います。

4

2 に答える 2

14

SynchronizationContext.Postまたは Send メソッドを使用できます。これは移植可能であり、ディスパッチャーで UI フレームワークを使用すると、現在の同期コンテキストが作業を Dispatcher に委任します。

具体的には、次のコードを使用できます。

void InvokeIfRequired(this SynchroniationContext context, Action action)
{
    if (SynchroniationContext.Current == context)
    {
        action();
    }
    else
    {
        context.Send(action) // send = synchronously
        // context.Post(action)  - post is asynchronous.
    }  
}
于 2012-06-29T08:20:08.133 に答える
2

TPLの登場により。タスクを返し、新しい async および await キーワードを使用して await'ed できる、受け入れられた回答のわずかに改善されたバージョンを思いつきました。

public Task RunAsync(Action action)
{
    TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();

    if (this.synchronizationContext == SynchronizationContext.Current)
    {
        try
        {
            action();
            taskCompletionSource.SetResult(null);
        }
        catch (Exception exception)
        {
            taskCompletionSource.SetException(exception);
        }
    }
    else
    {
        // Run the action asyncronously. The Send method can be used to run syncronously.
        this.synchronizationContext.Post(
            (obj) => 
            {
                try
                {
                    action();
                    taskCompletionSource.SetResult(null);
                }
                catch (Exception exception)
                {
                    taskCompletionSource.SetException(exception);
                }
            }, 
            null);
    }

    return taskCompletionSource.Task;
}
于 2013-10-07T13:39:43.173 に答える