views:

431

answers:

2

Hello,

I'm trying to call Dispatcher.PushFrame() from several different thread but encounter an error:

Must create DependencySource on same Thread as the DependencyObject.

Here is a code snippet:

_lockFrame = new DispatcherFrame(true);
Dispatcher.PushFrame(_lockFrame);

When I tried:

Dispatcher.CurrentDispatcher.Invoke(
    DispatcherPriority.Normal,
    new Action(() => _lockFrame = new DispatcherFrame(true));
Dispatcher.PushFrame(_lockFrame);

I get the error:

Objects must be created by the same thread.

What is the approach for pushing multiple frames into the Dispatcher from different threads?

A: 

Each thread has its own dispatcher object - returned by Dispatcher.CurrentDispatcher

The approach would be to cache the target dispatcher object once by calling the above method on the UI Thread. Then use _cachedObj.Invoke like you have - to marshal it across to the right thread.

WPF UI has 'thread affinity' - UI can only be accessed by the thread that creates it.

Update: Not sure of what you're trying to achieve. But the following code-snippet worked for me.

    private Dispatcher _dispatcher;
    private DispatcherFrame _lockFrame;
    public Window1()
    {
        InitializeComponent();

        _dispatcher = Dispatcher.CurrentDispatcher;

        // the other thread
        Thread t = new Thread(
            (ThreadStart)delegate
            {

                _dispatcher.Invoke(
                    (Action)delegate
                    {
                        var frame = CreateNewFrame();
                        Dispatcher.PushFrame(frame);
                    });
            });
        t.Start();
Gishu
I have tried this but continue to get the Objects must be created by the same thread. error.
Tri Q
@Tri Q: see update. Not sure if your problem can be solved with a different approach though... the above code makes me cringe.
Gishu
what is in CreateNewFrame()? Is that equivalent to 'new DispatcherFrame(true);'
Tri Q
@Tri Q: Yes. Sorry about that... kinda left it out.
Gishu
+3  A: 

Calling PushFrame on the same dispatcher from different threads just doesn't make sense, you didn't write what problem you are trying to solve but your PushFrame-based solution is probably wrong.

The Dispatcher object is responsible for executing code and dispatching event for a single thread, each thread has a queue of messages that are sent by the OS and include notifications for thing like mouse clicks, the dispatcher has a loop that reads this queue and calls the appropriate event.

Sometimes you have to process messages without returning from your method to the dispatcher loop, a good example for this is modal dialogs that respond to user input (so they need to process messages) without interrupting the control flow of the method that called them.

That what PushFrame does - it runs the dispatcher loop inside your code.

Each thread (optionally) has it's own message queue, the messages are specific to the windows and controls that belong to that thread, you can't process a thread's message queue from another thread (Windows itself doesn't have an API that let you read another thread's messages).

Calling PushFrame from another thread can't work because you're call happen on the wrong thread, PushFrame itself has to be called on the same thread manages by the dispatcher, you can't call it on another thread because that's trying to process a thread's messages on another thread.

Using Invoke or BeginInvoke also doesn't make sense here because the delegate passed to those methods is called only when the dispatcher is processing messages, if the dispather is already processing messages there's no need to call PushFrame to make it process messages.

If you ask another question describing what you are trying to do someone here may be able to help you, but calling Dispatcher.PushFrame from different threads is never going to work.

Nir
Thank you, this is a good explanation! The problem is exactly as you described. A modal dialog box that is thread safe. So basically how do I use one (1) single modal dialog box to handle Show() request from multiple threads?
Tri Q
Do you want a modal dialog that will block multiple threads until it closes?
Nir
Yes, thats what i'm looking for. A multi-threaded modal dialog.
Tri Q