I searched and got that Dispatcher CheckAccess can be used in place of InvokeRequired in wpf.
This is the code want to convert in wpf
private void ChangeTextBox(string txt)
{
if (msg_log.InvokeRequired)
{
Invoke(new UpdateText(ChangeTextBox), new object[] { txt });
}
else
{
msg_log.Text += txt + "\r\n";
}
}
I tried out this ---->
private void ChangeTextBox(string txt)
{
if (msg_log.Dispatcher.CheckAccess())
{
Dispatcher.Invoke(new UpdateText(ChangeTextBox), new object[] { txt });
}
else
{
msg_log.Text += txt + "\r\n";
}
}
But while running i am getting Error [InvalidOperationException] "The calling thread cannot access this object because a different thread owns it."
What i am doing wrong ? Please Help ?
Your problem is not because of the CheckAccess method... it is fine to use that to check whether the call to Invoke is required or not. When you call the Dispatcher, it is important to ensure that you are calling the correct instance of the Dispatcher class. From the Dispatcher Class page on MSDN:
In WPF, a DispatcherObject can only be accessed by the Dispatcher it is associated with. For example, a background thread cannot update the contents of a Button that is associated with the Dispatcher on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous.
So in your case, if you can access the correct Dispatcher instance using the following:
msg_log.Dispatcher.CheckAccess()
Then as #SriramSakthivel mentioned in the comments, you should access the same instance when calling Invoke:
msg_log.Dispatcher.Invoke(new UpdateText(ChangeTextBox), new object[] { txt });
OP problem solved but just for record a useful helper for dispatcher check is:
public void DispatchIfNecessary(Action action) {
if (!Dispatcher.CheckAccess())
Dispatcher.Invoke(action);
else
action.Invoke();
}
which can then be called as:
DispatchIfNecessary(() => { myUIcontrol.Update(...); });
Related
So I currently have this code below, which has a background worker call showdialog(). However, I thought that the UI cannot be updated on a background thread, so how does the dialog display? Does the dialog actually get opened on the UI thread? what happens?
public partial class ProgressDialog : Window
{
BackgroundWorker _worker;
public BackgroundWorker Worker
{
get { return _worker; }
}
public void RunWorkerThread(object argument, Func<object> workHandler)
{
//store reference to callback handler and launch worker thread
workerCallback = workHandler;
_worker.RunWorkerAsync(argument);
//display modal dialog (blocks caller)
//never returns null, but is a nullable boolean to match the dialogresult property
ShowDialog();
}
I have gotten suggestions that I just run the code and check, but how do i check whether the show dialog window was opened on a new thread or on the background thread itself? Not sure how I would check that.
Anyway this was just a post to try to help my understanding of what is actually happening in my code.
Anyway finally understood more of the comments, so I think I understand everything that is going on. Most of my real problems weren't caused by this dialog anyway, they were caused by updating observable collections from a non-ui thread while controls were bound to them.
Technically you are not changing a property on your Main thread just creating a instance of another object.
But it could help if you elaborate a bit more on your method ShowDialog().
I had also problem with calling ShowDialog() from non-UI thread. And my answer is that it depends on the thread which calls the ShowDialog(). If you set the ApartamentState property for this thread before its start then everything will work as called from the UI thread. I have finally ended up with such a code:
private async void button1_Click(object sender, EventArgs e)
{
var foo = new Foo();
// MessageBox.Show(foo.DirPath) - this works as a charm but
// if, it is called from non UI thread needs special handling as below.
await Task.Run(() => MessageBox.Show(foo.DirPath));
}
public class Foo
{
private string dirPath;
public string DirPath
{
get
{
if (dirPath == null)
{
var t = new Thread(() =>
{
using (var dirDialog = new FolderBrowserDialog())
{
if (dirDialog.ShowDialog() == DialogResult.OK)
dirPath = dirDialog.SelectedPath;
}
}
);
t.IsBackground = true;
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
}
return dirPath;
}
set
{
dirPath = value;
}
}
}
I dont know for sure but i thought that the showDialog doesnt create the object only showing it. So when u say ShowDialog it only tells to show. So it will run on the UI thread instead of the backgroundworker
(dont know for sure)
I have a c# .NET winforms app making this async call:
simpleDelegate.BeginInvoke(null, null);
My function is being called by the delegate and that all works great. The problem is, after the function finishes on the worker thread, I need the main thread to update some controls on my winform. If the worker thread tries to update these controls, .NET freaks out. But I need the main thread to remain responsive to user actions, and then call my function UpdateFormAfterServerCall() ONLY AFTER the worker thread finishes calling the async function.
I would greatly appreciate if you can give me a concise code sample, rather than abstractly explain how to do this. I've read a hundred explanations already, and am just having trouble wiring it together correctly.
Note: Before the BeginInvoke I have:
simpleDelegate = new MethodInvoker(CallServer);
From different thread if you want to update GUI which is owned by another thread use MethodInvoker
if(control.InvokeRequired)
control.Invoke( (MethodInvoker) ( ()=> updating_function() ) );
else
updating_function();
You could use a BackgroundWorker:
BackgroundWorker bw = new BackgroundWorker();
string result = null;
bw.DoWork += (s, e) =>
{
// Executes on background thread.
// UI remains responsive to user activity during this time.
result = CallServer();
};
bw.RunWorkerCompleted += (s, e) =>
{
// Executes on UI thread upon completion.
resultTextBox.Text = result;
};
bw.RunWorkerAsync();
The Control class (Form is a Control as well) has an Invoke method, you can call this from any thread to execute code on the GUI thread.
In addition, Control has a convenient InvokeRequired property that informs you whether you are on the GUI thread already. You could for instance create the following method in your form:
public class MyForm
{
// ...
public void UpdateMe()
{
if (InvokeRequired)
{
Invoke(new Action(UpdateMe));
return;
}
// Code to update the control, guaranteed to be on the GUI thread
}
}
Here is the code sample [what you want exactly] -
http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
& you can read about all flavours of async here -
http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.100).aspx
I have an Exception Handling project in my application that can be called from anywhere to show the user there is a problem with with system. Everything works great when the call is made from somewhere in the UI as expected. When I make calls from no UI parts of the application everything freezes. I have the code wrapped in the thread safe calls and when stepping through they don't require the Invoke call. Any help is greatly appreciated. Code below:
Inside the form
void err_DispEvent(string text)
{
if (InvokeRequired)
{
Invoke(new Error.DisplayDelegate(err_DispEvent), new object [] {text});
}
else
{
this.Show();
}
}
Call from the class
public void FaultError(string errorMsg)
{
FaultForm fform = new FaultForm(errorMsg, "Internal Fault");
if (this.dispEvent != null)
{
dispEvent(errorMsg);
}
}
public event DisplayDelegate DispEvent
{
add { dispEvent += value; }
remove { dispEvent -= value; }
}
private event DisplayDelegate dispEvent;
public delegate void DisplayDelegate(string text);
Sample of how the class is used in the application
ECDUExceptions.Error newError = ECDUExceptions.Error.getInstance();
newError.FaultError("Heater is not responding to function calls, it has been turned off");
Some information when re-invoking methods:
Use BeginInvoke(...) instead of Invoke(...) as this will not wait for the call to finish, and so won't freeze the calling thread.
Use an Action when re-invoking. So in your case, you could change your invocation to:
BeginInvoke(new Action<string>(err_DispEvent), text);
Use BeginInvoke(...) instead of Invoke(...). THis will put your message request in the end of the queue
Create a queue of some sort for the messages that should be displayed.
Fill the queue from whatever thread you required.
From the GUI responsible for showing the messages, use timer to dequeue and show them.
Simplistic but will work effortlessly. And you won't need to Invoke() anything since Forms.Timer runs on UI message loop.
I have a worker thread that needs to add items to a BindingList. However, the BindingList is databound to a DataGridView. So, when I try to add to the list, I get an InvalidOperationException (Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.)
Normally for this exception you would do:
if(winformControl.InvokeRequired) {
winformControl.Invoke(MethodDelegate);
}
However, the databinding confuses things, as there is no Winform control in sight. All I have is the following line, which throws the exception:
ClassInstance.MyBindingList.Add(myObject);
If you have a solution specifically for this scenario, great.
If not, how can I get the worker thread to tell my main thread to perform a particular method (with several parameters supplied by the worker thread)? This may be a preferable option, since my worker thread is actually doing a bunch of stuff at the moment (like writing to the database), and I'm not sure if everything is thread-safe. I'm a student, and new to multithreading, and it really is not my forte yet.
One option here is to tell BindingList<T> to use the sync-context, like this - however, this is arguably not the best approach. I wonder if you could expose your data via an event or similar (rather than adding to the list directly) - then have your UI handle the event by sending to the right thread and adding to the UI model.
In your worker class constructor, try this:
private System.Threading.SynchronizationContext mContext = null;
/// <summary>
/// Constructor for MyBackgroundWorkerClass
/// </summary>
public MyBackgroundWorkerClass(System.Threading.SynchronizationContext context)
{
mContext = context;
}
Then, when you need to invoke something on the UI thread:
private void CallOnTheUiThread(object dataToPassToUiThread)
{
// Make sure the code is run on the provided thread context.
// Make the calling thread wait for completion by calling Send, not Post.
mContext.Send(state =>
{
// Change your UI here using dataToPassToUiThread.
// Since this class is not on a form, you probably would
// raise an event with the data.
}
), null);
}
When creating your worker class from a form on the UI thread, this is what you would pass as the synchronization context.
private void Form1_Load(object sender, EventArgs e)
{
var worker = new MyBackgroundWorkerClass(SynchronizationContext.Current);
}
You can fire an event to the main, UI, thread and there have:
if (this.InvokeRequired)
{
this.Invoke(...);
}
so you are testing on the main Window itself.
BackgroundWorkers are easy to implement if you are able to given the requirements.
Define a DoWork method that runs on a background thread such as saves to the database. The RunWorkerCompleted method is called when DoWork finishes. RunWorkerCompleted runs on the UI thread, and you can update the view's list with no problems.
// on the UI thread
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += RunWorkerCompleted;
worker.RunWorkerAsync("argument");
Events:
static void DoWork(object sender, DoWorkEventArgs e)
{
e.Result = "4";
}
static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
string a = (string)e.Result;
Console.WriteLine(a);
}
else
{
Console.WriteLine(e.Error.Message);
}
}
MethodInfo mi = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(notify, null);
This throws the following exception:
{"Exception has been thrown by the target of an invocation."}
With the following inner exception:
"Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on."
If I comment out a line of code that sets the images for the context menu entries then it stops throwing the exception.
Any ideas?
You may be confusing the Invoke method of MethodInfo, which just invokes the delegate on the current thread, with Control.Invoke which invokes a delegate on the UI thread.
You get this exception if you try to access a UI element from a thread other than the correct UI thread.
Basically you need to execute this code on the UI thread instead.
Is there any reason why you're trying to invoke ShowContextMenu via reflection instead of directly? You may just need something like (assuming C# 3):
MethodInvoker action = () => notify.ShowContextMenu();
someControl.Invoke(action);
You are updating UI controls on a thread other than the thread that created them. That is not allowed.
In regular code you can use the Control.InvokeRequired property.
Assuming that you have a form with two buttons, and two labels here is how to do updates from another thread:
private void button1_Click(object sender, EventArgs e)
{
//force execution on another thread
new Thread(updateLabelThreaded).Start();
}
private void button2_Click(object sender, EventArgs e)
{
//force execution on another thread
new Thread(updateLabelReflect).Start();
}
private void updateLabelThreaded()
{
if (!label1.InvokeRequired)
{
//if we are on the correct thread, do a trivial update
label1.Text = "something";
}
else
{
//else invoke the same method, on the UI thread
Invoke(new Action(updateLabelThreaded), null);
}
}
private void updateLabelReflect()
{
Control ctrl = label2;
PropertyInfo pi = typeof (Label).GetProperty("InvokeRequired");
bool shouldInvoke = (bool) pi.GetValue(ctrl, null);
if (!shouldInvoke)
{
//if we are on the correct thread, reflect whatever is neccesary - business as usual
PropertyInfo txtProp = typeof (Label).GetProperty("Text");
txtProp.SetValue(ctrl, "Something 2", null);
}
else
{
//else invoke the same method, on the UI thread
Invoke(new Action(updateLabelReflect), null);
}
}
You can't call UI methods from a non-UI thread. I recommend using TaskScheduler.FromCurrentSynchronizationContext to marshal the call to the UI thread.