可移植类库,相当于Dispatcher.Invoke或Dispatcher.RunAsync

Muh*_*eed 10 .net c# dispatcher task-parallel-library portable-class-library

在.NET,Windows 8和Windows Phone 7中,我的代码与此类似:

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

我如何在便携式类库中做一些事情?有一个平台无关的实现这将是很好的.我的想法是使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我唯一不确定的是它的性能影响.也许我会做一些测试.

Ale*_*tof 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.
    }  
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,Metro风格应用程序不支持SynchronizationContext.Send-您将收到NotSupportedException.因此,该方法在便携式类库中已被标记为过时.请参阅http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.send(v=vs.110).aspx (4认同)

Muh*_*eed 2

随着TPL的出现。我提出了一个稍微改进的已接受答案的版本,它返回一个任务,并且可以使用新的 async 和 await 关键字进行等待。

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 好的。看起来您创建了一个类,但只发布了方法,因此为其他人提供了(可能是显而易见的)注释。在调用方法之前,必须在您希望操作运行的线程中分配 this.synchronizationContext。我实际上对上面进行了一些修改并创建了一个扩展:public Task RunAsync(this SynchronizationContext context, Action action)。现在它更像是原始答案,因为它可以独立存在。两个答案中最好的。:) (2认同)