2010-04-05 7 views
25

Tôi đã gặp vấn đề truy cập Chủ đề chéo không hợp lệ, nhưng một ít nghiên cứu và tôi đã cố gắng khắc phục sự cố bằng cách sử dụng Trình điều phối.Tìm hiểu về Silverlight Dispatcher

Bây giờ trong ứng dụng của tôi, tôi có các đối tượng bị tải chậm. Tôi muốn thực hiện một cuộc gọi Async sử dụng WCF và như thường lệ tôi sử dụng Dispatcher để cập nhật các đối tượng của tôi DataContext, tuy nhiên nó không làm việc cho kịch bản này. Tuy nhiên tôi đã tìm thấy một giải pháp here. Đây là những gì tôi không hiểu.

Trong UserControl của tôi, tôi có mã để gọi một phương thức Chuyển đổi trên đối tượng của tôi. Các cuộc gọi đến phương pháp này là trong một Dispatcher như vậy.

Dispatcher.BeginInvoke(() => _CurrentPin.ToggleInfoPanel()); 

Như tôi đã đề cập trước đây không đủ để thỏa mãn Silverlight. Tôi phải thực hiện một số khác Cuộc gọi của người điều phối trong đối tượng của tôi. Đối tượng của tôi là KHÔNG phải là UIElement, nhưng là một lớp đơn giản xử lý tất cả tải/tiết kiệm của riêng nó.

Vì vậy, vấn đề đã được cố định bằng cách gọi

Deployment.Current.Dispatcher.BeginInvoke(() => dataContext.Detail = detail); 

trong lớp học của tôi.

Tại sao tôi phải gọi cho Điều phối viên hai lần để đạt được điều này? Chẳng phải một cuộc gọi cấp cao là đủ sao? Có sự khác biệt nào giữa Deployment.Current.Dispatcher và Dispatcher trong UIElement không?

+1

Tôi không nghĩ rằng bạn cung cấp đủ mã. Tôi sẽ nghi ngờ một cái gì đó bạn đang làm là bắn một cuộc gọi mạng, đó là trở lại trong một chủ đề nền, do đó hai gọi? –

Trả lời

21

Lý tưởng nhất là lưu trữ một phiên bản Dispatcher duy nhất mà bạn có thể sử dụng ở nơi khác mà không cần kiểm tra chuỗi.

Gọi bất kỳ singleton nào. Hiện tại có thể thực tế gây ra kiểm tra quyền truy cập qua luồng được gọi. Bằng cách lưu trữ nó đầu tiên, bạn có thể tránh điều này để thực sự có được cá thể được chia sẻ.

Tôi sử dụng "SmartDispatcher" sử dụng bộ điều phối khi được gọi tắt, và chỉ cần gọi khác. Nó giải quyết vấn đề này.

bài viết: http://www.jeff.wilcox.name/2010/04/propertychangedbase-crossthread/

Code:

// (c) Copyright Microsoft Corporation. 
// This source is subject to the Microsoft Public License (Ms-PL). 
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. 
// All other rights reserved. 

using System.ComponentModel; 

namespace System.Windows.Threading 
{ 
    /// <summary> 
    /// A smart dispatcher system for routing actions to the user interface 
    /// thread. 
    /// </summary> 
    public static class SmartDispatcher 
    { 
     /// <summary> 
     /// A single Dispatcher instance to marshall actions to the user 
     /// interface thread. 
     /// </summary> 
     private static Dispatcher _instance; 

     /// <summary> 
     /// Backing field for a value indicating whether this is a design-time 
     /// environment. 
     /// </summary> 
     private static bool? _designer; 

     /// <summary> 
     /// Requires an instance and attempts to find a Dispatcher if one has 
     /// not yet been set. 
     /// </summary> 
     private static void RequireInstance() 
     { 
      if (_designer == null) 
      { 
       _designer = DesignerProperties.IsInDesignTool; 
      } 

      // Design-time is more of a no-op, won't be able to resolve the 
      // dispatcher if it isn't already set in these situations. 
      if (_designer == true) 
      { 
       return; 
      } 

      // Attempt to use the RootVisual of the plugin to retrieve a 
      // dispatcher instance. This call will only succeed if the current 
      // thread is the UI thread. 
      try 
      { 
       _instance = Application.Current.RootVisual.Dispatcher; 
      } 
      catch (Exception e) 
      { 
       throw new InvalidOperationException("The first time SmartDispatcher is used must be from a user interface thread. Consider having the application call Initialize, with or without an instance.", e); 
      } 

      if (_instance == null) 
      { 
       throw new InvalidOperationException("Unable to find a suitable Dispatcher instance."); 
      } 
     } 

     /// <summary> 
     /// Initializes the SmartDispatcher system, attempting to use the 
     /// RootVisual of the plugin to retrieve a Dispatcher instance. 
     /// </summary> 
     public static void Initialize() 
     { 
      if (_instance == null) 
      { 
       RequireInstance(); 
      } 
     } 

     /// <summary> 
     /// Initializes the SmartDispatcher system with the dispatcher 
     /// instance. 
     /// </summary> 
     /// <param name="dispatcher">The dispatcher instance.</param> 
     public static void Initialize(Dispatcher dispatcher) 
     { 
      if (dispatcher == null) 
      { 
       throw new ArgumentNullException("dispatcher"); 
      } 

      _instance = dispatcher; 

      if (_designer == null) 
      { 
       _designer = DesignerProperties.IsInDesignTool; 
      } 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <returns></returns> 
     public static bool CheckAccess() 
     { 
      if (_instance == null) 
      { 
       RequireInstance(); 
      } 

      return _instance.CheckAccess(); 
     } 

     /// <summary> 
     /// Executes the specified delegate asynchronously on the user interface 
     /// thread. If the current thread is the user interface thread, the 
     /// dispatcher if not used and the operation happens immediately. 
     /// </summary> 
     /// <param name="a">A delegate to a method that takes no arguments and 
     /// does not return a value, which is either pushed onto the Dispatcher 
     /// event queue or immediately run, depending on the current thread.</param> 
     public static void BeginInvoke(Action a) 
     { 
      if (_instance == null) 
      { 
       RequireInstance(); 
      } 

      // If the current thread is the user interface thread, skip the 
      // dispatcher and directly invoke the Action. 
      if (_instance.CheckAccess() || _designer == true) 
      { 
       a(); 
      } 
      else 
      { 
       _instance.BeginInvoke(a); 
      } 
     } 
    } 
} 
+0

Công cụ awsome, cảm ơn bạn! – Matt

+1

Đây là công cụ tuyệt vời và cố định di cư của tôi. – slashp

6

Nếu bạn sử dụng MVVM light toolkit bạn có thể sử dụng lớp DispatcherHelper trong không gian tên Galasoft.MvvmLight.Threading trong dll Extras. Nó kiểm tra truy cập và sử dụng một thuộc tính tĩnh cho điều phối viên, tương tự như SmartDispatcher.

Trong App.xaml.cs khởi động gọi sự kiện của bạn:

DispatcherHelper.Initialize(); 

Sau đó, bất cứ nơi nào bạn cần sử dụng một sử dụng phối:

DispatcherHelper.CheckBeginInvokeOnUI(() => // do stuff;); 
+1

Liên kết không chính xác. Đây là: http://mvvmlight.codeplex.com/ – paulwhit

+0

Tôi đã sửa liên kết, cảm ơn. – Aligned