Acording to my understanding Dispatcher.Invoke and Dispatcher.BeginInvoke executes on UI thread, The only difference is That Invoke is synchronous and BeginInvoke is asynchronous.My problem is when i use this code
EDisc.App.Current.Dispatcher.
Invoke(
DispatcherPriority.Normal, new Action(delegate
{
context = NavigationManager.CurrentPage.DataContext;
}));
Value of context is returned. However with the below code
EDisc.App.Current.Dispatcher.
BeginInvoke(
DispatcherPriority.Normal, new Action(delegate
{
context = NavigationManager.CurrentPage.DataContext;
}));
Context is null and i get an InvalidOperation Exception saying "
The calling thread cannot access this object because a different thread owns it.I am calling this from a WCF service which is executing with UseSynchronizationContext = false .Can anybody explain this behaviour?
Both BeginInvoke and Invoke will end up calling an internal method called BeginInvokeImpl to do the work. The difference is that Invoke then waits for the operation to complete before returning.
And there's one other difference: if you are already on the UI thread and you're using DispatcherPriority.Send Invoke will actually invoke the method directly without going via BeginInvokeImpl, meaning that the operation is processed without going via the message queue. (If you're not using Send then any other messages already queued up with higher property than your operation will get processed first.)
But since you're presumably not on the UI thread here - you're on some WCF callback - that special case won't apply. So Invoke ends up calling into the same underlying implementation as BeginInvoke.
From the information you've provided, I'd have to guess that there's a missing detail somewhere here. The code you've shown should work fine, unless perhaps you have multiple UI threads in your application, and the page that happens to be in CurrentPage belongs to different threads from time to time.
If you do have multiple UI threads, then the approach you're using - pushing everything through the current Application object's dispatcher - isn't going to work, because you'll have multiple dispatchers. You'd need to get the right dispatcher for whichever UI element you're planning to touch.
Incidentally, one way you might accidentally end up with multiple UI threads is if you construct a UI object (e.g. a Page) on some worker thread or callback. Is it possible that you've done that somewhere?
Related
I am supposed to work on a wpf legacy application( and desktop app is a new beast for me).
I have read that consumming task should not be launched on the ui thread : but I find this following code in the code behind of a view :
bool isSearching = true;
try
{
Task<ProductSearchResult>.Factory
.StartNew(() => DBCatalogService.Search( search.Criteria, search.CriteriaPage, search.CriteriaResultByPage)
.ContinueWith(res => LoadResult(res, search.Criteria, search.CriteriaPage, search.CriteriaResultByPage),
TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith(s => isSearching = false);
}
catch
{
...
}
I am wondering it will not cause any trouble.
I know that it's sounds weird to call the database directly from the view code behind, but I just want to know if it could freeze the ui thread or something like this.
Thank you for your advice on this matter.
My question is : does the sample code that I provided would block the UI thread and have to be considered harmfull or not ?
The call to the DBCatalogService.Search method will not block the UI thread since it is being invoked on a background thread using the task parallel library (TPL).
The call to the LoadResult method will however be executed on the UI thread once the task that calls the Search method has completed.
This is fine though since this method probably sets some properties of some UI elements based on the result of the search and you must do this on the UI thread. This is because WPF controls have thread affinity, meaning that a control can only be accessed on the thread on which it was originally created.
So no, the sample code you have provided should not be considered "harmfull" in terms of UI responsiveness assuming that the LoadResult doesn't perform any strange and potentially long-running operations.
If you block the UI thread (dispatcher thread) with a long-running operation such as a synchronous DB request, your application will be unresponsive until the thread is unblocked.
You can avoid this by either:
Doing the blocking/synchronous operation on another thread
Making the operation non-blocking/asynchronous
Both of the above
Using async/await can make your code read much like the synchronous form, but with asynchronous behaviour. It should be much clearer than the code sample you give in the question. However you need an async form of your search.
If you do use another thread, remember to dispatch back onto the UI thread if you have to update UI properties.
This method call sits inside a class derived from DispatcherObject:
Dispatcher.Invoke(DispatcherPriority.Input, new ThreadStart(() =>
{
var exported = formatProvider.Export(original.Workbook);
Workbook = formatProvider.Import(exported);
}));
The method on the class is called by a backgroundworker in its DoWork delegate.
Workbook is Telerik's Workbook, as used by the RadSpreadsheetControl. Obviously, workbooks can only be accessed by the UI thread.
The above code throws an InvalidOperationException, saying
The calling thread must be STA, because many UI components require
this.
I don't really understand, as I thought that when invoking the actions with a Dispatcher, I would be calling it from the UI Thread, which is STA?
What am I missing here and how can this be fixed? Or should this work in general and the bug is somewhere else? What could be a reason then?
TL;DR: You must create this DispatcherObject inside your UI thread, not in a worker.
DispatcherObject.Dispatcher, which you are marshalling the operation to, is set to Dispatcher.CurrentDispatcher at the time of the object's construction. If the object is not created inside your existing UI thread then the documented behavior of CurrentDispatcher is to create a new dispatcher object associated with the thread. Later on, Invoke tries to marshal the call to that thread (which is not STA) resulting in the error.
It is not sufficient to use a class derived from DispatcherObject. You must use the Dispatcher from an existing UIElement created from XAML (or at least make sure, you create your class from inside the GUI thread where it picks the right Dispatcher).
I want to render a chart with the DevExpress ChartControl via the WiForm DrawToBitmap() function on a separate thread.
I try something like:
Form yourForm;
Thread thread = new Thread( () =>
{
yourForm = new HiddenForm();
Application.Run(yourForm);
});
thread.ApartmentState = ApartmentState.STA;
thread.Start();
yourForm.Invoke(chartRenderingFunction)
And simple make sure the Hidden never actually gets displayed. However, I don't need that hidden form, and there is a parameterless form of Application.Run(). However, if I run that, it doesn't return. So my question is once I call Application.Run() inside a thread, how do I inject code in it?
Well, you actually really do need that hidden window. The only way to get code to run on that thread. Somebody must call PostMessage() and that requires a window handle. Your Invoke() call makes that call. You really should use BeginInvoke() instead, there's no point in starting a thread if you are going to wait for the call to complete.
Using Application.Run(yourForm) is going to make the window visible. You can stop it from becoming visible by overriding the SetVisibleCore() method in your HiddenForm class:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
CreateHandle();
value = false;
ThreadReady.Set();
}
base.SetVisibleCore(value);
}
The CreateHandle() call is necessary to make sure that the window is created so it can process the PostMessage() notifications. Also note the added AutoResetEvent (ThreadReady), you are going to have to call ThreadReady.WaitOne() after calling the thread's Start() method to ensure that your BeginInvoke() call is going to work. Dispose the form to get the thread to exit or call Application.Exit().
Last but not least, be very careful with using non-trivial controls on that thread. A chart control certainly is not indicated. You'll have long-lasting problems if that control uses the SystemEvents class for example. Your worker thread will get it to raise events on that worker thread. But it won't be around anymore after the chart is printed. You'll now get the events fired on an arbitrary threadpool thread, very nasty. A deadlock is a common mishap, particularly apt to trigger when locking the workstation.
I wonder whether it is possible to understand which code pieces are executed on UI from source code just depending on static analysis in Windows Phone development.
I try to implement a static analysis finding places in which Dispatcher.(Begin)Invoke is used unnecessarily.
These are the places that UI thread definitely executes:
event handlers which gets "RoutedEventArgs" as a parameter
Constructors of UI elements
the definitions of method calls in above methods (means that transitively looking at call graphs of these event handler methods and UI constructors)
Is there any other place or is there something wrong about above list?
Every method called by using the Dispatcher or the right SynchronizationContext will execute on the UI thread. That makes exhaustive static analysis impossible. For instance, the callback of the WebClient class executes on the UI thread. How are you supposed to predict those corner cases?
A quick tip though, quite useful is you have a method that can be called both from a UI or a non-UI thread. By calling the method Dispatcher.CheckAccess() (this method isn't shown by the intellisense in Visual Studio, so it's hard to discover), you can know if you need to call the Dispatcher or not:
if (Dispatcher.CheckAccess())
{
// In the UI thread
SomeMethod();
}
else
{
// Not in the UI thread
Dispatcher.BeginInvoke(SomeMethod);
}
From there, you can write a wrapper:
public void CallDispatcherIfNeeded(Action method) // You might want a shorter name
{
if (Dispatcher.CheckAccess())
{
// In the UI thread
method();
}
else
{
// Not in the UI thread
Dispatcher.BeginInvoke(method);
}
}
And then you just have to call it, without worrying whether you're on the UI thread or not:
CallDispatcherIfNeeded(SomeMethod);
That said, if your code is correctly written, it's quite rare to need this kind of trick.
I would look at when Dispatcher.BeginInvoke is actually needed, not the other way around.
It is almost never needed, excepted when handing an async completed event which may start out on a background thread, and thus if you want to do something with the UI, you need to marshal it over to the UI thread.
In other words, unless you need to do something with the UI from a background thread, you don't need it.
Greg
Why i should call Control.Invoke from non-ui thread? As i know any manipulations with control are the messages to control. So when i call, for example TextBox.Text = "text", it will produce message SendMessage(TextBox.Hanlde...). That message will be queued into UI thread message queue and dispatched by UI thread. Why i have to call invoke, even it will produce the same message?
There are two reasons MS developers made this restriction:
Some UI functions have access to thread-local storage (TLS). Calling these functions from another thread gives incorrect results on TLS operations.
Calling all UI-related functions from the same thread automatically serializes them, this is thread-safe and doesn't require synchronization.
From our point of view, we just need to follow these rules.
Because you cannot directly access UI controls from threads other than the thread they were created on. Control.Invoke will marshal your call onto the correct thread - allowing you to make a call from another thread onto the UI thread without needing to know yourself what the UI thread is or how to perform the marshalling.
Update: to answer your question, you don't have to use Control.Invoke - if you have code to marshal your call onto the correct thread and post a message to the message pump - then use that. This, however, is known as re-inventing the wheel. Unless you are doing something that changes the behaviour.