9

Trong .NET, Windows 8 và Windows Phone 7 tôi có mã tương tự như sau:di động thư viện lớp tương đương của Dispatcher.Invoke hoặc Dispatcher.RunAsync

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

Làm thế nào tôi sẽ làm một cái gì đó trong thư viện lớp cầm tay? Sẽ thật tuyệt khi có một nền tảng triển khai độc lập về điều này. Ý tưởng của tôi là sử dụng TPL mà không có sẵn trong WP7 nhưng chắc chắn sẽ sớm.

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

Điều duy nhất tôi không chắc chắn về ý nghĩa hiệu suất của việc này là gì. Có lẽ tôi sẽ làm một số xét nghiệm.

Trả lời

2

Với sự ra đời của TPL. Tôi đã đưa ra một phiên bản cải tiến một chút của câu trả lời được chấp nhận trả về một nhiệm vụ và có thể được chờ đợi bằng cách sử dụng async mới và chờ đợi từ khóa.

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

Tốt. Có vẻ như bạn đã tạo một lớp nhưng chỉ đăng phương thức để ghi chú (có thể hiển nhiên) cho người khác. this.synchronizationContext phải được gán trong chuỗi bạn muốn hành động chạy trước khi gọi phương thức. Tôi thực sự sửa đổi ở trên một chút và tạo ra một phần mở rộng: public Task RunAsync (bối cảnh SynchronizationContext này, Action action). Bây giờ nó giống như câu trả lời ban đầu vì nó có thể đứng một mình. Tốt nhất của cả hai câu trả lời. :) – Wes

13

Bạn có thể sử dụng phương thức SynchronizationContext.Post hoặc Gửi. Nó là di động, và khi bạn sử dụng một khung giao diện người dùng với một điều phối thì bối cảnh đồng bộ hóa hiện tại sẽ ủy nhiệm công việc cho Dispatcher.

Cụ thể, bạn có thể sử dụng đoạn mã sau:

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

Tốt nhất. Bạn sẽ tạo phương thức mở rộng mà tôi sử dụng ở trên cho điều phối viên như thế nào. Cụ thể như thế nào để bạn kiểm tra xem bạn đã chạy trên thread UI thay vì làm dispatcher.CheckAccess() chưa. –

+0

Ngoài ra là Post the Equivelant của BeginInvoke và Gửi equivelant của Invoke? –

+1

Bạn không cần kiểm tra trước khi đăng. Đăng đã thực hiện kiểm tra thích hợp. –