2010-02-05 21 views
6

Tôi có một chương trình với bản đồ Geospace được nhúng vào trong đó. Việc xử lý sự kiện cho bản đồ được xử lý trên một chuỗi riêng biệt để giữ cho bản đồ đáp ứng (ví dụ: các sự kiện kích hoạt khi bản đồ được nhấp vào).C#, WPF, Tự động gọi Dispatcher.Invoke khi cần?

Sự cố tôi gặp phải là khi bản đồ kích hoạt sự kiện, chương trình của tôi cần cập nhật một số thứ trong gui của nó và cũng có thể gọi lại bản đồ để xử lý việc đặt ảnh trên bản đồ.

Tôi đã thử gói toàn bộ phương thức xử lý sự kiện trong this.Dispatcher.Invoke, điều này đặt tôi trở lại luồng giao diện người dùng chính. Điều này hoạt động rất tốt cho việc cập nhật GUI của tôi, nhưng khi tôi gọi lại vào bản đồ, tôi vẫn đang ở trên chuỗi giao diện người dùng có thể gây ra một số vấn đề trong bản đồ.

Về cơ bản, để thực hiện công việc này, tôi sẽ phải chạy dispatcher.invoke mỗi khi tôi muốn thay đổi điều khiển trên gui của mình. Có cách nào tôi có thể tự động làm điều này mà không gói mỗi cuộc gọi trong dispatcher.invoke? Tôi hy vọng tất cả điều này có ý nghĩa.

Heres một số mã ví dụ cho sự kiện tôi đang nói về ..

private void Map_OnMapClicked(object sender, MapClickedEventArgs e) 
    { 
     this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => 
     { 
      // Do something to update my gui 
     })); 

     Map.DoSomethingInTheMap(); 

     this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => 
     { 
      // Do something to update my gui 
     })); 


     //etc etc etc 
    } 

Trả lời

6

Nếu bạn cần phải giữ cho mỗi hoạt động tương ứng trong bối cảnh đồng bộ hóa riêng của mình, đây là tiếc là phương pháp tốt nhất. Bạn sẽ cần gọi Invatcher bằng cách sử dụng Dispatcher bất cứ khi nào bạn cập nhật GUI của mình.

Dưới đây là một vài gợi ý cho việc này dễ dàng hơn:

  1. Cố gắng hàng loạt các hoạt động giao diện đồ họa của bạn. Ngoài việc yêu cầu ít mã hơn (thông qua các lệnh gọi ít hơn), bạn sẽ nhận được hiệu suất tốt hơn. Mỗi cuộc gọi Dispatcher.Invoke mang một số tiền hợp lý trên không, vì nó gửi một thông điệp vào hàng đợi thông điệp của Dispatcher mà phải được xử lý.

  2. Cân nhắc sử dụng Dispatcher.BeginInvoke để tránh chặn, trừ khi bạn thực sự cần phải đợi.

  3. Nếu bạn có thể sử dụng Thư viện song song nhiệm vụ từ .NET 4 (hoặc cổng sau đến 3.5sp1 trong khung Rx), bạn có thể xem xét làm lại điều này để sử dụng Task instances synchronized to the GUI thread. Bằng cách tạo một TaskScheduler bằng cách sử dụng FromCurrentSynchronizationContext, bạn có thể lên lịch các tác vụ để chạy trên GUI dễ dàng hơn các cuộc gọi Dispatcher Invoke. Điều này cũng có thể cung cấp cho bạn một số kiểm soát đối với việc tạo nhóm, vì bạn có thể lên lịch cho chúng và chặn/đợi khi cần, rất dễ dàng.

2

Bạn có thể sử dụng giống như PostSharp hay cố gắng cô đọng cập nhật giao diện người dùng của bạn để phương pháp duy nhất gọi là nơi bạn gọi một lần và làm được rất nhiều. Hoặc thậm chí một mô hình như thế này (đó là Winforms nhưng ý tưởng là như nhau):

private void UpdateToolStripItemText(ToolStripItem toolStripItem, string text) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new UpdateToolStripItemTextDelegate(UpdateToolStripItemText), new object[] { toolStripItem, text }); 
    } 
    else 
    { 
     if (text != null) 
     { 
      toolStripItem.Text = text; 
     } 
    } 
} 
Các vấn đề liên quan