9

的在.NET中,Windows 8和Windows Phone 7的我有類似下面的代碼:便攜式類庫相當於Dispatcher.Invoke或Dispatcher.RunAsync

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

我怎麼會做便攜式類庫的東西嗎?有一個平臺不可知的實現這將是很好的。我的想法是使用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); 
    } 
} 

我不確定的唯一的事情就是性能的影響。也許我會做一些測試。

回答

2

隨着第三方物流的出現。我想出了一個稍微改進的接受答案,它返回一個任務,並可以使用新的異步和等待關鍵字等待。

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; 
} 
+2

不錯。看起來你創建了一個類,但只是把這個方法發佈給其他人。在調用方法之前,必須在想要操作的線程中分配this.synchronizationContext。我實際上修改了一下,並創建了一個擴展:public Task RunAsync(此SynchronizationContext上下文,Action action)。現在它更像原來的答案,因爲它可以單獨使用。兩種答案都是最好的。 :) – Wes

13

您可以使用SynchronizationContext.Post或Send方法。它是可移植的,並且當您使用帶有調度程序的UI框架時,當前同步上下文會將工作委託給分派器。

具體地說,可以使用下面的代碼:

void InvokeIfRequired(this SynchroniationContext context, Action action) 
{ 
    if (SynchroniationContext.Current == context) 
    { 
     action(); 
    } 
    else 
    { 
     context.Send(action) // send = synchronously 
     // context.Post(action) - post is asynchronous. 
    } 
} 
+0

不錯。你將如何創建我在調度器上面使用的擴展方法。具體來說,你如何檢查你是否已經在UI線程上運行,而不是執行dispatcher.CheckAccess()。 –

+0

也是發佈BeginInvoke的Equivelant併發送調用Equivelant? –

+1

在發佈之前,您不需要檢查。郵政已經做了適當的檢查。 –