9

Taşınabilir sınıf kütüphanesi eşdeğer Ben buna benzer bir kod vardır:.NET, Windows 8 ve Windows Phone 7'de Dispatcher.Invoke veya Dispatcher.RunAsync

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

nasıl taşınabilir sınıf kitaplığında bir şey yapsın? Bunun bir platformun agnostik uygulamasının olması güzel olurdu. Benim fikrim, WP7’de mevcut olmayan TPL’i kullanmaktır, ancak kesinlikle yakında olacaktır.

// 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); 
    } 
} 

Emin olmadığım tek şey bunun performans açısından ne anlama geleceğidir. Belki bazı testler yapacağım.

cevap

2

:

Özellikle, aşağıdaki kodu kullanabilirsiniz. Kabul edilen cevabın biraz geliştirilmiş bir versiyonunu buldum, bu da bir görevi döndürüyor ve yeni async'i kullanarak anahtar kelimeleri bekliyor.

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

Güzel sorar. Bir sınıf oluşturduğunuza benziyor ancak sadece yöntemi başkaları için (belki de açık) bir not olarak gönderiyorsunuz. this.synchronizationContext, yöntemi çağırmadan önce işlemin yürütülmesini istediğiniz iş parçacığına atanmalıdır. Aslında biraz üzerinde değişiklik yaptım ve bir uzantı yarattım: public Task RunAsync (bu SynchronizationContext içeriği, Eylem eylemi). Artık tek başına durabildiği için orijinal cevabı gibi. Her iki cevabın en iyisi. :) – Wes

13

SynchronizationContext.Post veya Gönderme yöntemini kullanabilirsiniz. Taşınabilirdir ve bir dağıtıcı ile bir UI çerçevesi kullandığınızda, o zaman geçerli senkronizasyon içeriği işi Dispatcher'e devreder. VUK gelişiyle birlikte

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

Güzel olan. Dağıtıcı için yukarıda kullandığım uzantı yöntemini nasıl oluşturursunuz? Özellikle dispatcher.CheckAccess() yerine UI iş parçacığı üzerinde çalışıyor olup olmadığını nasıl kontrol edersiniz. –

+0

Ayrıca BeginInvoke Denklemini Gönder ve Invoke eşdeğerini gönder? –

+1

Göndermeden önce kontrol etmeniz gerekmez. Mesaj zaten uygun kontrolleri yapıyor. –