How do I wait for the result from Dispatcher Invoke? - c#

I think I'm missing something here. I've got a WPF form that has some methods on it I need to call from an external source (usually on a non-UI thread). I retrieve a reference to the form, then attempt to call the method via Dispatcher.Invoke so it's marshalled to the UI thread. The problem is that this code won't work as the Invoke fires an Action, so the result is always an empty string (even though the docs say Invoke is supposed to be synchronous).
public string GetValueById(string id, string value)
{
Application.Current.Dispatcher.Invoke(() =>
{
var main = Application.Current.MainWindow as MainWindow;
if (main != null)
{
return main.GetValue(id);
}
});
return "";
}
I can't quite wrap my head around how to make this work.

If you look at the documentation for that Dispatcher.Invoke overload, you'll see that if you pass it a Func<TResult> callback then it will return the TResult returned by executing that callback. All you have to do is actually make use the return value:
public string GetValueById(string id, string value)
{
return Application.Current.Dispatcher.Invoke(() =>
{
var main = Application.Current.MainWindow as MainWindow;
if (main != null)
{
return main.GetValue(id);
}
});
}

Related

Background Task sometimes able to update UI?

I just answered a question about whether a Task can update the UI. As I played with my code, I realized I'm not clear myself on a few things.
If I have a windows form with one control txtHello on it, I'm able to update the UI from a Task, it seems, if I immediately do it on Task.Run:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Task.Run(() =>
{
txtHello.Text = "Hello";
});
}
}
However if I Thread.Sleep for even 5 milliseconds, the expected CrossThread error is thrown:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Task.Run(() =>
{
Thread.Sleep(5);
txtHello.Text = "Hello"; //kaboom
});
}
}
I'm not sure why that happens. Is there some sort of optimization for an extremely short running Task?
You didn't post the exception stack trace, but I expect that it looked something like this:
System.InvalidOperationException: Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.set_WindowText(String value)
at System.Windows.Forms.TextBoxBase.set_WindowText(String value)
at System.Windows.Forms.Control.set_Text(String value)
at System.Windows.Forms.TextBoxBase.set_Text(String value)
at System.Windows.Forms.TextBox.set_Text(String value)
at WindowsFormsApplicationcSharp2015.Form1.<.ctor>b__0_0() in D:\test\WindowsFormsApplicationcSharp2015\Form1.cs:line 27
We can see that the exception is thrown from the Control.Handle getter property. And in fact, if we look at the source code for that property, there it is, as expected:
public IntPtr Handle {
get {
if (checkForIllegalCrossThreadCalls &&
!inCrossThreadSafeCall &&
InvokeRequired) {
throw new InvalidOperationException(SR.GetString(SR.IllegalCrossThreadCall,
Name));
}
if (!IsHandleCreated)
{
CreateHandle();
}
return HandleInternal;
}
}
The interesting part is when we look at the code that calls Control.Handle. In this case, that's the Control.WindowText setter property:
set {
if (value == null) value = "";
if (!WindowText.Equals(value)) {
if (IsHandleCreated) {
UnsafeNativeMethods.SetWindowText(new HandleRef(window, Handle), value);
}
else {
if (value.Length == 0) {
text = null;
}
else {
text = value;
}
}
}
}
Notice that the Handle property is only invoked if IsHandleCreated is true.
And for completeness, if we look at the code for IsHandleCreated we see the following:
public bool IsHandleCreated {
get { return window.Handle != IntPtr.Zero; }
}
So, the reason you don't get the exception, is because by the time the Task executes, the window handle hasn't been created yet, which is to be expected since the Task starts in the form's constructor, that is, before the form is even displayed.
Before the window handle is created, modifying a property doesn't yet require any work from the UI thread. So during this small time window at the start of your program, it would seem that it is possible to invoke the methods on control instances from a non-UI thread without getting the "cross thread" exception. But clearly, the existence of this special small time window doesn't change the fact that we should always make sure to invoke control methods from the UI thread to be safe.
To prove the point that the timing of the window handle creation is the determining factor in getting (or not) the "cross thread" exception, try modifying your example to force the creation of the window handle before you start the task, and notice how you will now consistently get the expected exception, even without a sleep:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Force creation of window handle
var dummy = txtHello.Handle;
Task.Run(() =>
{
txtHello.Text = "Hello"; // kaboom
});
}
}
Relevant documentation: Control.Handle
If the handle has not yet been created, referencing this property will force the handle to be created.

Comparing SynchronizationContext

How do I compare SynchronizationContext? It seems that the same Dispatcher can create different SynchronizationContext when using BeginInvoke. When I drill down into the two (unequal) contexts, I see that the dispatcher Thread ID is the same, yet they are not Equal to each other.
public partial class MainWindow : Window
{
private SynchronizationContext contexta;
private SynchronizationContext contextb;
private SynchronizationContext contextc;
private SynchronizationContext contextd;
public MainWindow()
{
InitializeComponent();
contexta = SynchronizationContext.Current;
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
contextb = SynchronizationContext.Current;
Dispatcher.Invoke(() =>
{
contextc = SynchronizationContext.Current;
});
Dispatcher.BeginInvoke(new Action(() =>
{
contextd = SynchronizationContext.Current;
}));
Debug.Assert(contexta != contextb);
Debug.Assert(contexta == contextc); // fails... why?!?!?
Debug.Assert(contexta == contextd); // fails... why?!?!?
Debug.Assert(contextc == contextd); // fails... why?!?!?
}
Maybe the two of them cannot be used together. I noticed that this actually works:
contexta.Send(new SendOrPostCallback((s) =>
{
contexte = SynchronizationContext.Current;
}), null);
Update But strangely, it doesn't always work.
public override void AddRange(IEnumerable<T> items)
{
if (SynchronizationContext.Current == _context)
{
base.AddRange(items);
}
else
{
_context.Send(new SendOrPostCallback((state) =>
{
AddRange(state as IEnumerable<T>);
}), items);
}
}
never gets a matched _context and goes on forever, for example. Even though it shouldn't. This latter example the threads actually end up being the same, and there is a context, but it is different.
Update2 Ok, I got it to work, but I really feel uncomfortable about it. Apparently, when you Post or Send, your task is run from the right thread, but if you aren't coming from the UI, it seems that a new SynchronizationContext is generated.
public override void AddRange(IEnumerable<T> items)
{
if (SynchronizationContext.Current == _context)
{
base.AddRange(items);
}
else
{
_context.Post(new SendOrPostCallback((state) =>
{
if (SynchronizationContext.Current != _context)
SynchronizationContext.SetSynchronizationContext(_context); // called every time.. strange
AddRange(items);
}), null);
}
}
And look at this:
"Requires full trust for the immediate caller. This member cannot be used by partially trusted or transparent code." :(
I think you are interested in
BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance.
This setting dictates whether a single SynchronizationContext instance is used for a given Dispatcher object or not. It is true by default until .net 4, and false in .net 4.5 (this is the behavior change that LukeN observes).
Now if your goal is just to make a direct call rather than calling .Send() I'd say:
when calling .Send(), the DispatcherSynchronizationContext actually just makes a direct call if you are on the correct thread (doesn't use the dispatcher Queue) so you're not gaining much anyway (a few checks and calls from the extra layers of indirection).
if you only code against WPF, you can use Dispatcher.CheckAccess() and Dispatcher.Invoke() to do what you want.
In the general case, there is no way to "compare" two SynchronizationContexts, so you should just call .Send(). It's not likely to be a performance issue anyway, remember that premature optimization is the root of all evil -> measure first.

AgrumenNullException in ThreadPool.QueueUserWorkItem

I've got a method which gets called frequently by different treads. Sometimes I get an AgrumenNullException when ThreadPool.QueueUserWorkItem(display(angebot), null); gets called, stating that the parameter callBack (the first parameter) is null.
What am I doing wrong?
public class ai : UserControl
{
//...
public void Display(Angebote angebot)
{
lock (_syncObj) { _current = angebot; }
ThreadPool.QueueUserWorkItem(display(angebot), null);
}
private WaitCallback display(Angebote angebot)
{
// doing something
}
//...
}
The ThreadPool.QueueUserWorkItem will do the work as defined in the WaitCallback delegate returned by display(Angebote). I would surmise that your display method sometimes returns null.
Is your intent to execute display(angebot) in the background thread, or does that method discern what method should be executed?
If you're thinking that your display method should be executing in a background thread:
private WaitCallback display(Angebote angebot)
{
// doing something in a background thread
}
Then your code should look like:
ThreadPool.QueueUserWorkItem(display, angebot);
private void display(object state)
{
Angebot angebot = (Angebot)state;
// doing something in a background thread
}
EDIT: If it's the latter where display is figuring out what background thread to execute, then perhaps you have something looking like this:
private WaitCallback display(Angebote angebot)
{
if (angebot.Something)
{
return new WaitCallback(BackgroundTask1);
}
else
{
return null;
}
}
But since you haven't posted that code, I'm not sure. In this case, returning null is invalid for ThreadPool.QueueUserWorkItem.

Invoke without Func in Property's getter for .Net 2.0

I would like to use Invoke in getter, how to do it when using .Net 2.0 not e.g. 4.0? For .Net > 2.0 we can use Func and what is replacement for .Net 2.0?
Here is example for .Net 4.0 (from link)
public ApplicationViewModel SelectedApplication
{
get {
if (this.InvokeRequired)
{
return (ApplicationViewModel)this.Invoke(new Func<ApplicationViewModel>(() => this.SelectedApplication));
}
else
{
return _applicationsCombobox.SelectedItem as ApplicationViewModel;
}
}
}
Since you're using .NET 2.0, you won't have the Func delegate available to you, but you can use the MethodInvoker delegate.
You won't be able to use the lambda expression syntax with .NET 2.0, but you can use the "anonymous delegate" syntax (which is pretty much the same thing), as shown in the code example below.
Querying data in UI controls from a non-UI thread is generally an uncommon thing to do; usually your UI controls trigger events that execute on the UI thread, so you gather the data you need from your UI controls at that time and then pass that data on to some other function, so you don't need to worry about doing an Invoke.
In your case, though, you should be able to do something like this:
public ApplicationViewModel SelectedApplication
{
get
{
if (this.InvokeRequired)
{
ApplicationViewModel value = null; // compiler requires that we initialize this variable
// the call to Invoke will block until the anonymous delegate has finished executing.
this.Invoke((MethodInvoker)delegate
{
// anonymous delegate executing on UI thread due calling the Invoke method
// assign the result to the value variable so that we can return it.
value = _applicationsCombobox.SelectedItem as ApplicationViewModel;
});
return value;
}
else
{
return _applicationsCombobox.SelectedItem as ApplicationViewModel;
}
}
}
EDIT: Now that I look at your .NET 4.0 code sample and also look at the Invoke function, I see how it can return a value (not something that I've had a reason to use before).
Well, the MethodInvoker delegate does not expect a return value, but as #haiyyu pointed out, you could define your own delegate. For instance, you would just need to define your own Func<TResult> delegate, and the original code would probably work fine:
// this is all that is required to declare your own Func<TResult> delegate.
delegate TResult Func<TResult>();
Sample code from the MSDN page:
public partial class Form1 : Form
{
public Form1()
{
// Create a timer that will call the ShowTime method every second.
var timer = new System.Threading.Timer(ShowTime, null, 0, 1000);
}
private void ShowTime(object x)
{
// Don't do anything if the form's handle hasn't been created
// or the form has been disposed.
if (!this.IsHandleCreated && !this.IsDisposed) return;
// Invoke an anonymous method on the thread of the form.
this.Invoke((MethodInvoker) delegate
{
// Show the current time in the form's title bar.
this.Text = DateTime.Now.ToLongTimeString();
});
}
}
Use delegates, they are a sort of typed function pointers.
Here's some more reading: http://msdn.microsoft.com/en-us/library/ms173171%28v=vs.80%29.aspx

Solve a cross-threading Exception in WinForms

Presently I'm working with WinForms(in C#) and I have to run the application in the background. For this purpose I'm using asynchronous. When I run the application it's showing an exception like
"Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on."
How can I solve this error?
When making method calls to a control, if the caller is on a different thread than the one the control was created on, you need to call using Control.Invoke. Here is a code sample:
// you can define a delegate with the signature you want
public delegate void UpdateControlsDelegate();
public void SomeMethod()
{
//this method is executed by the background worker
InvokeUpdateControls();
}
public void InvokeUpdateControls()
{
if (this.InvokeRequired)
{
this.Invoke(new UpdateControlsDelegate(UpdateControls));
}
else
{
UpdateControls();
}
}
private void UpdateControls()
{
// update your controls here
}
Hope it helps.
Most often, the best way to do this sort of thing with WinForms is to use BackgroundWorker, which will run your work on a background thread, but provide you with a nice clean way to report status back to the UI.
In a lot of everyday .NET programming, explicitly creating threads or calling .Invoke is a sign that you're not using the framework to its full advantage (of course, there are lots of legitimate reasons to do low-level stuff too, it's just that they're less common that people sometimes realise).
You need to check if Invoke is required for the control you're trying to update. Something like this:
Action<Control, string> setterCallback = (toSet, text) => toSet.Text = text;
void SetControlText(Control toSet, string text) {
if (this.InvokeRequired) {
this.Invoke(setterCallback, toSet, text);
}
else {
setterCallback(toSet, text);
}
}
Updated from Invoke to begin Invoke
// you can define a delegate with the signature you want
public delegate void UpdateControlsDelegate();
public void SomeMethod()
{
//this method is executed by the background worker
InvokeUpdateControls();
}
public void InvokeUpdateControls()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateControlsDelegate(UpdateControls));
}
else
{
UpdateControls();
}
}
private void UpdateControls()
{
// update your controls here
}
A pattern you might find useful is to do a check at the top of functions that interact with the GUI to see whether you are running on the correct thread or not and have the function invoke itself if required. Like this:
public delegate void InvocationDelegate();
public void DoGuiStuff(){
if (someControl.InvokeRequired){
someControl.Invoke(InvocationDelegate(DoGuiStuff));
return;
}
//GUI manipulation here
}
Using this pattern - if you are on the correct thread when the method is called it doesn't invoke itself, but if you are on a different thread it will invoke itself and then return (so the GUI manipulation logic is only ever called once either way).
The UI changes can be done with Control.Invoke() methods, this cross thread exception can be solved using below code snippet.
void UpdateWorker()
{
//Here ddUser is the user control
//Action to be performed should be called within { } as like below code
if (this.ddUser.InvokeRequired)
ddUser.Invoke(new MethodInvoker(() => { ddUser.Size = new Size(100, 100); }));
}
I knew the topic is 10 years old, but I would like to improve the solution for generic through lambda selector instead of defining of each type of setter
private void SetControlSafety<C, V>(C control, Expression<Func<C, V>> selector, V value)
{
if (this.InvokeRequired)
this.Invoke(MyUtils.GetSetter(selector), control, value);
else
DataCrawlerUtils.GetSetter(selector)(control, value);
}
Or static
public static void SetControlSafety<C, V>(C control, Expression<Func<C, V>> selector, V value) where C : Control
{
if (control.InvokeRequired)
control.Invoke(DataCrawlerUtils.GetSetter(selector), control, value);
else
DataCrawlerUtils.GetSetter(selector)(control, value);
}
GetSetter method from here to assign value to a property has been selected through lambda
public static Action<T, TProperty> GetSetter<T, TProperty>(
Expression<Func<T, TProperty>> pExpression
)
{
var parameter1 = Expression.Parameter(typeof(T));
var parameter2 = Expression.Parameter(typeof(TProperty));
// turning an expression body into a PropertyInfo is common enough
// that it's a good idea to extract this to a reusable method
var member = (MemberExpression)pExpression.Body;
var propertyInfo = (PropertyInfo)member.Member;
// use the PropertyInfo to make a property expression
// for the first parameter (the object)
var property = Expression.Property(parameter1, propertyInfo);
// assignment expression that assigns the second parameter (value) to the property
var assignment = Expression.Assign(property, parameter2);
// then just build the lambda, which takes 2 parameters, and has the assignment
// expression for its body
var setter = Expression.Lambda<Action<T, TProperty>>(
assignment,
parameter1,
parameter2
);
return setter.Compile();
}
Then the using is pretty simple
SetControlSafety(txtStatus, x => x.Text, "Loading resources...");
BeginInvoke
It is a good way to prevent a cross-thread exception. I read it in a book "The C# Programmer’s Study Guide (MCSD"
You can use BeginInvoke
BeginInvoke method is used to change values of UI control from other threads. It does it in a thread-safe way. It requires a delegate; it tells which UI control needs to change its value.
private async void button1_Click(object sender, EventArgs e)
{
Task task = Task.Run(() =>
{
this.BeginInvoke(new Action(() =>
{
label1.Text = "Hello";
}));
});
await task;
}
The value of label1.Text shall be changed to “Hello” and no exception will arise because it’s a threadsafe operation.

Categories

Resources