Wednesday, April 27, 2011

WPF: Dispatcher - Application Startup

In my last post, I mentioned that "the Dispatcher" is created automagically at startup. Time to cut through the magic and see what's really happening.


I started up VS.NET 2010, created a new WPF Application called "SimpleApplication", and built and ran the initial pieces dropped in by the project template. In the "obj\x86\Debug" path under the main project folder, I found the automatically generated "App.g.cs" source file, created as a product of my App's build action being set to ApplicationDefinition:
    /// <summary>
    /// App
    /// </summary>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks""4.0.0.0")]
    public partial class App : System.Windows.Application {
       
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public void InitializeComponent() {
           
            #line 4 "..\..\..\App.xaml"
            this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
           
            #line default
            #line hidden
        }
       
        /// <summary>
        /// Application Entry Point.
        /// </summary>
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public static void Main() {
            SimpleApplication.App app = new SimpleApplication.App();
            app.InitializeComponent();
            app.Run();
        }
    }
This file doesn't make any explicit references to the Dispatcher class, but we can at least see our Main() method now, so something that it's doing must be bringing about that initial Dispatcher instantiation. Looking through all of the partial source files for App.cs, we know that no explicit ctor has been declared, so the construction of our new App instance seems to have no effect beyond the creation of the new object. We can clearly see what InitializeComponent() is doing, so app.Run() must be behind all of the Dispatcher initialization, right?

Using my new best friend ILSpy, I walked down through the Application.Run call chain until I found the first place where the Dispatcher was accessed, hopping through Run(Window) and RunInternal() before landing at RunDispatcher():
// System.Windows.Application
[SecurityCritical]
private object RunDispatcher(object ignore)
{
    if (this._ownDispatcherStarted)
    {
        throw new InvalidOperationException(SR.Get("ApplicationAlreadyRunning"));
    }
    this._ownDispatcherStarted = true;
    Dispatcher.Run();
    return null;
}

The call to Dispatcher.Run() is really two statements in one: it gets the Application.Dispatcher property and then tells that dispatcher to start its loop. The Dispatcher property is defined on Application's base class, DispatcherObject, and is defined like this:
// System.Windows.Threading.DispatcherObject
[EditorBrowsable(EditorBrowsableState.Advanced)]
public Dispatcher Dispatcher
{
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    get
    {
        return this._dispatcher;
    }
}


Um, okay, this must mean that the _dispatcher instance field is initialized somewhere else. The constructor maybe?
// System.Windows.Threading.DispatcherObject
protected DispatcherObject()
{
    this._dispatcher = Dispatcher.CurrentDispatcher;
}



Aha! So it all boils down to Dispatcher.CurrentDispatcher, which makes loads of sense, though I had expected there to be some lazy initialization involved here.
// System.Windows.Threading.Dispatcher
public static Dispatcher CurrentDispatcher
{
    get
    {
        Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread);
        if (dispatcher == null)
        {
            dispatcher = new Dispatcher();
        }
        return dispatcher;
    }
}


So there you go. Since we haven't created a dispatcher on our current thread yet, Dispatcher.CurrentDispatcher makes one for us.


There are two main takeaways form this analysis:
  • The Dispatcher for an executable is created the moment the Application object is constructed.
  • Creating any instance of a DispatcherObject has the side effect of creating a Dispatcher on the calling thread.
[Afrojack: Bangduck -- YouTube]

1 comment:

  1. UPDATE: After further review, the call to Dispatcher.Run() in the RunDispatcher() method above was interpreted incorrectly. The Run() method is static, so this is actually relying on the Dispatcher class to figure out what dispatcher instance should be affected (the one associated with the calling thread).

    ReplyDelete