you don't have to add a lock, Dispatcher.Invoke and BeginInvoke requests will not run in the middle of other code (that's the whole point of them).
Just two things to consider:
- BeginInvoke may be more appropriate in this case, Invoke will queue the request and then block the calling thread until the UI thread becomes idle and finishes executing the code, BeginInvoke will only queue the request without blocking.
- Some operations, especially operations that open windows (including message boxes) or do inter-process communication may allow the queued dispatcher operations to run.
EDIT: first, I don't have citations because the MSDN pages on the subject are unfortunately very low on details - but I have written test programs to check the behavior of BeginInvoke and everything I write here is the result of those tests.
now, to expand on the second point we first need to understand what the dispatcher does, obviously this is a very simplified explanation.
Any Windows UI work by processing messages, for example when the user moves the mouse over a window the system will send that window a WM_MOUSEMOVE message.
The system send the message by adding it a queue, each thread may have a queue, all windows created by the same thread share the same queue.
In the heart of every Windows program there's a loop called "message loop" or "message pump", this loop reads the next message from the queue and calls the appropriate window's code to process that message.
In WPF this loop and all the related processing handled by the Dispatcher.
An application can either be in the message loop waiting for the next message or it could be doing something, that is why when you have a long calculation all the thread's windows become unresponsive - the thread is busy working and doesn't return to the message loop to process the next message.
Dispatcher.Invoke and BeginInvoke work by queuing the requested operation and executing it the next time the thread returns to the message loop.
That is why Dispather.(Begin)Invoke can't "inject" code in the middle of your method, you won't get back to the message loop until your method returns.
BUT
Any code can run a message loop, when you call anything that runs a message loop the Dispatcher will be called and can run the (Begin)Invoke operations.
What kinds of code has a message loop?
- Anything that has a GUI or that excepts user input, for example dialog boxes, message boxes, drag&drop etc. - if those didn't have a message loop than the app would have been unresponsive and unable to handle user input.
- Inter-process communication that uses windows messages behind the scenes (most inter-process communication methods, including COM, use them).
- Anything else that takes a long time and doesn't freeze the system (the fast that the system isn't frozen is proof it's processing messages).
So, to summerize:
- the Dispatcher can't just drop code into your thread, it can only execute code when the application is in the "message loop".
- Any code you write doesn't have message loops unless you explicitly wrote them.
- Most UI code doesn't have it's own message loop, for example if you call Window.Show and then do some long calculation the window will only appear after the calculation is finished and the method returns (and the app returns to the message loop and processes all the messages required to open and draw a window).
- But any code that interacts with the user before it returns (MessageBox.Show, Window.ShowDialog) has to have a message loop.
- Some communication code (network and inter-process) uses message loops, some doesn't, depending on the specific implementation you are using.