Understanding the Silverlight Dispatcher

后端 未结 2 381
无人及你
无人及你 2020-12-14 01:32

I had a Invalid Cross Thread access issue, but a little research and I managed to fix it by using the Dispatcher.

Now in my app I have objects with lazy loading. I\'

相关标签:
2条回答
  • 2020-12-14 02:08

    Ideally, store a single instance of Dispatcher that you can use elsewhere without having the thread check on it.

    Calling any singleton .Current instance may in fact cause a cross-thread access check to be invoked. By storing it first, you can avoid this to actually get the shared instance.

    I use a "SmartDispatcher" that uses a dispatcher when called off-thread, and just invokes otherwise. It solves this sort of issue.

    Post: 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 讨论(0)
  • 2020-12-14 02:14

    If you use the MVVM light toolkit you could use the DispatcherHelper class in the Galasoft.MvvmLight.Threading namespace in the Extras dll. It checks the access and uses a static property for the dispatcher, similar to the SmartDispatcher.

    In your App.xaml.cs startup event call:

    DispatcherHelper.Initialize();
    

    Then anywhere you need to use a dispatcher use:

       DispatcherHelper.CheckBeginInvokeOnUI(() => // do stuff; );
    
    0 讨论(0)
提交回复
热议问题