14

I am trying to create a second thread with dispatcher so that I can have the primary dispatcher (for the UI) completely stress-free, and have the UI constantly respondant.

Now, I could create multiple threads for each sub (or void in C#), but isn't it possible for me to create one new thread and grab it's dispatcher, and invoke to that? This is what I've done:

Private CheckLoopThread As New System.Threading.Thread(New System.Threading.ThreadStart(AddressOf CheckLoop))

CheckLoopThread.Priority = System.Threading.ThreadPriority.Lowest
CheckLoopThread.Start()
Dim Test As Windows.Threading.Dispatcher = Windows.Threading.Dispatcher.FromThread(CheckLoopThread)

However, the variable "Test" is after execution "Nothing". How is this possible? Is the another way to create a second dispatcher?

Answers are appreciated in any .NET form. Visual Basic or C#. I am working in VB.NET WPF on the .NET 4.0 framework.

Thanks in advance.

djv
  • 15,168
  • 7
  • 48
  • 72
René Sackers
  • 2,395
  • 4
  • 24
  • 43

3 Answers3

18

Why locking?

I prefer:

Dispatcher myDispatcher = null;

// create a manual reset event for crossthread signalling.
var dispatcherReadyEvent = new ManualResetEvent(false);

// create a new thread.
new Thread(new ThreadStart(() =>
{
    // get the current dispatcher (if it didn't exists
    // it will be created.
    myDispatcher = Dispatcher.CurrentDispatcher;
    // set the signal that the dispatcher is created.
    dispatcherReadyEvent.Set();
    // run the dispatcher.
    Dispatcher.Run();
})).Start();

// wait until the dispatcher is created on the thread.
dispatcherReadyEvent.WaitOne();

// run something on the dispatcher thread.
myDispatcher.Invoke(...);
Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57
13

Dispatcher.FromThread(...) will not create a Dispatcher and will return null if a Dispatcher has not already been created for the thread. To create a Dispatcher for a thread, you will have to access Dispatcher.CurrentDispatcher at least once on your CheckLoopThread. As it says on MSDN for Dispatcher.CurrentDispatcher:

If a Dispatcher is not associated with the current thread, a new Dispatcher will be created. This is not the case with the FromThread method. FromThread will return null if there is not a dispatcher associated with the specified thread

Glenn Slayden
  • 17,543
  • 3
  • 114
  • 108
Jakob Christensen
  • 14,826
  • 2
  • 51
  • 81
  • Thank you so much! That indeed was it. +1 For you. – René Sackers Jul 18 '11 at 01:25
  • An important note and warning for those using **.NET Reflector** from RedGate (still in 2021 at least, as of version 10.3.1.1956...), the product displays *patently incorrect C#* for the simple two-line function `Dispatcher.get_CurrentDisptacher`. The code incorrectly claims that a `new Dispatcher()` is created every time the `Dispatcher.CurrentDispatcher` property is accessed. But by switching to the product's **IL** display, you can see that this is not the case. – Glenn Slayden Feb 12 '21 at 00:46
  • Another warning in this area (unrelated to the bug I just mentioned) is that the design by Microsoft here is quite confusing. Namely: `Dispatcher.CurrentDispatcher` is a (static) ***"property with side-effects"*** (boo!), while the (static) ***method*** `Dispatcher.FromThread(...)`—which basically does the same thing—is actually ***non-*** *side-effecting*. A design which swaps the semantics of these two would be clearer and would generate far fewer faulty expectations. – Glenn Slayden Feb 12 '21 at 01:36
5

I'm actually creating a lot of these dispatchers, I guess the proper way is something along the following lines:

object theLock = new object();
Dispatcher dispatcher = null;

lock (theLock)
{
    new Thread(new ThreadStart(() =>
    {
        lock (theLock)
        {
            dispatcher = Dispatcher.CurrentDispatcher;
            Monitor.Pulse(theLock);
        }
        Dispatcher.Run();
    })).Start();

    Monitor.Wait(theLock);
}

dispatcher.Invoke(...);

It seems complicated with all the locking, but theoretically the Start() method can return before dispatcher is actually set, so a call to to it might result in a NullReferenceException without the locks.

mycroes
  • 645
  • 8
  • 20