I’m doing some stuffs in thread and I’m try to access the label property, but I can’t to set the property value.
lblDisplay.Visible = true;
I’m getting an error on this.
Error - Cross-thread operation not valid: Control 'lblDisplay' accessed from a thread other than the thread it was created on.
Thanks in advance.
You should use the BeginInvoke method on the form to set the variable on the same thread it's running on, for example:
this.BeginInvoke((Action)delegate{ lblDisplay.Visible = true; });
Most people will tell you to use the Invoke method instead but unless you absolutely NEED everything in the delegate to be run before any other code in the thread is executed you probably wont need it. Invoke will block the thread from processing any further until the delegate has completed, where as BeginInvoke will simply execute it in the thread the form is running in while simultaneously running the thread that began the invoke.
I think you first need to Check whether its need to invoke or not ( In some other case that same code may not need to invoke) so...
if(lblDisplay.InvokeRequired) {
lblDisplay.Invoke((Action)delegate{ lblDisplay.Visible = true; }); // For synchronous
lblDisplay.BeginInvoke((Action)delegate{ lblDisplay.Visible = true; }) // For asynchronous
}
else
{
lblDisplay.Visible=true;
}
You can’t directly access from a thread other than the thread it was created on. You can set that property value by using MethodInvoker.
lblDisplay.Invoke((MethodInvoker)(() => { lblDisplay.Visible = true; }));
This the way you need to access the control in different thread.
A Control can only be accessed within the thread that created it - the UI thread.
Try this,
Invoke(new Action(() =>
{
lblDisplay.Visible = true;
}));
Using this.BeginInvoke method with lambda :
this.BeginInvoke(new Action(() => { lblDisplay.Visible = true; }));
Reference : https://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke(v=vs.110).aspx
Related
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(...); });
I have a form whose focused state is checked in a method using:
if (!this.Focused)
{
//do something
}
However, this also needs to be checked from another worker thread, and I am getting cross thread violations when I call if (!this.Focused) from another thread . How can I access the true or false state of this.Focused boolean from another thread? I am familiar with using delegates to update form controls from other threads, but I am having a real issue with this. What am I missing? Any help is greatly appreciated.
It's exactly the same - you just need to use the return value of Invoke, which is the return value of the delegate:
Func<bool> func = () => this.Focused;
var focused = (bool) Invoke(func);
What about this?
bool focused = false;
this.Invoke((MethodInvoker)delegate
{
focused = controlname.Focused;
});
Try,
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
focused = controlname.Focused;
});
}
else
{
focused = controlname.Focused;
}
check more about InvokeRequired http://www.codeproject.com/Articles/37642/Avoiding-InvokeRequired
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 inherited some code that queries a DB over a WCF service and then employs a callback when it's done. I am trying to add some code to that callback to update the UI as the data is processed. I'm finding that I cannot get the UI to update during that callback:
client.GetDataAsync();
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted);
void GetDataCompleted(object sender, GetDataCompletedEventArgs e)
{
// Loop through the data
// ...
textBlock1.Text= "test1";
Dispatcher.BeginInvoke(() => textBlock1.Text= "test2" );
var thread = new Thread(() =>
{
// textBlock1.Text= "test3"; (this throws a cross-thread access exception)
Dispatcher.BeginInvoke(() =>
{
textBlock1.Text= "test4";
});
}
thread.Start();
// ...
Debug.WriteLine("done");
}
None of these things update the UI until (apparently) the entire callback is completed. This post:
What thread calls the completed event handler on silverlight WCF calls?
suggests that the callback is running on the main UI thread so that the BeginInvoke call should be unnecessary. Even if I add various delays in the above code, it still doesn't work. Is this possible? Is there a better way to do this?
(This is a follow-up question to this: Multiple asynchronous UI updates in Silverlight)
degorolls is right in suggesting the TPL, your code would look like below (except without the comments)(Also, exceptions MUST be handled in the TPL, so that might make it not worth it, but I dont think it should).
The first methods would remain the same, and yes in event-based async programming thread-safety is taken care of (ie: you always return to the same thread you called out from)
I also noticed that the text output is all doing = instead of +=, but that is probably more of a problem of typing into overflow
So, test1 and test2 will print out at the same time, however everything being spit out from the TPL code should print as it comes in.
UI code should not be doing anything that requires too much time, though...only updating the UI. So, do think of this as a point to refactor?
Let me know if this helps or if I missed what you were looking for.
client.GetDataAsync();
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted);
void GetDataCompleted(object sender, GetDataCompletedEventArgs e)
{
// Loop through the data
// ...
textBlock1.Text= "test1";
//////Dispatcher should not be needed here as this IS on the main UI thread
Dispatcher.BeginInvoke(() => textBlock1.Text= "test2" );
//////Everything that happens here should NOT be on the main UI thread, thus the cross-thread access exception
//////You can do Dispatcher.CheckAccess to determine if you need to invoke or not
//////Notice the newCopyOfDataToBeWritten. This is a closure,
//////so using the same referenced object will result in errant data as it loops
//////Also, doing it this way does not guarantee any order that this will be written out
//////This will utilize the parallel fully, but there are ways to force the order
var task = Task.Factory.StartNew(()=>
{
Dispatcher.BeginInvoke(()=>textBlock1.Text += newCopyOfDataToBeWritten)
}
);
// ...
///////I assume this is the end of the loop?
Debug.WriteLine("done");
}
....
the below dummied-down code based on what you posted seems to work for me
var outsideThread = new Thread(()=>
{
for(int i = 0; i < 20; i++)
{
//This code will show all at once since it is on the main thread,
//which is still running
//If you want this to display one at a time also, then you need
//to use threads and callbacks like below, also
Dispatcher.BeginInvoke(()=>{textBlock1.Text += "outer" + i;});
int newI = i;
var thread = new Thread(() =>
{
System.Threading.Thread.Sleep(1000 * newI);
Dispatcher.BeginInvoke(() =>
{
//This will display as it comes in
textBlock1.Text += "inner" + newI;
});
});
thread.Start();
}
});
outsideThread.Start();
if (listBox1.InvokeRequired)
{
listBox = new StringBuilder(this.listBox1.Text);
}
This is the code in c# which when executed produces an invalid cross thread operation error for listBox1 which is a listbox in my form.
Could u guys please tell me why??
I am using the invokeRequired method too and am not changing the contents of the listbox either.
InvokeRequired only tells you that an Invoke is necessary in order to validly access the element. It doesn't make the access legal. You must use the invoke method to push the update to the appropriate thread
Action update = () => listbox = new StringBuilder(this.listBox1.Text);
if (listBox1.InvokeRequired) {
listBox1.Invoke(update);
} else {
update();
}
InvokeRequired simply checks to see if Invoke is required. You found it's required, yet didn't call Invoke!
Your code should run when InvokeRequired is false
delegate void SetListBoxDelegate();
void SetListBox()
{
if(!InvokeRequired)
{
listBox = new StringBuilder(this.listBox1.Text);
}
else
Invoke(new SetListBoxDelegate(SetListBox));
}
Edit:
Check out Making Windows Forms thread safe