crossthread operations error - c#

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

Related

Cross-thread operation

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

Alternative to InvokeRequired

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(...); });

C# thread safe text update on dynamically created text boxes

I know how to do a thread safe update on a text box that was already defined http://msdn.microsoft.com/en-us/library/ms171728.aspx .... how can i do this on text boxes that were generated later on in the program? You advice is much appreciated.
Given some TextBox object, just invoke on it:
TextBox foo = new TextBox(...);
// Code to add the new box to the form has been omitted; presumably
// you do this already.
Action update = delegate { foo.Text = "Changed!"; };
if (foo.InvokeRequired) {
foo.Invoke(update);
} else {
update();
}
If you're using this pattern a lot, this extension method might be helpful:
public static void AutoInvoke(
this System.ComponentModel.ISynchronizeInvoke self,
Action action)
{
if (self == null) throw new ArgumentNullException("self");
if (action == null) throw new ArgumentNullException("action");
if (self.InvokeRequired) {
self.Invoke(action);
} else {
action();
}
}
Then you can reduce your code to:
foo.AutoInvoke(() => foo.Text = "Changed!");
This will just do the right thing, executing the delegate on the main GUI thread whether or not you are currently executing on it.
We definitely need more information here, but from what I can gather, you're lamenting the fact that the thread's main function doesn't take any arguments. You could make the textbox(es) members of the surrounding class, and access them that way. If you go this route though, be sure to use a mutex or some other locking device for threads.

Accessing Control.Focused true or false state from another thread

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

WPF invoke a control

How can I invoke a control with parameters? I've googled this up, but nowhere to find!
invoke ui thread
This is the error i get:
Additional information: Parameter count mismatch.
And this happens when i do a simple check whether the text property of a textbox control is empty or not. This works in WinForms:
if (this.textboxlink.Text == string.Empty)
SleepThreadThatIsntNavigating(5000);
It jumps from this if the line to the catch block and shows me that message.
This is how i try to invoke the control:
// the delegate:
private delegate void TBXTextChanger(string text);
private void WriteToTextBox(string text)
{
if (this.textboxlink.Dispatcher.CheckAccess())
{
this.textboxlink.Text = text;
}
else
{
this.textboxlink.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new TBXTextChanger(this.WriteToTextBox));
}
}
What am I doing wrong? And since when do i have to invoke a control when i just want to read its content?
When you call Invoke, you're not specifying your argument (text). When the Dispatcher tries to run your method, it doesn't have a parameter to supply, and you get an exception.
Try:
this.textboxlink.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new TBXTextChanger(this.WriteToTextBox), text);
If you want to read the value from a text box, one option is to use a lambda:
string textBoxValue = string.Empty;
this.textboxlink.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action( () => { textBoxValue = this.textboxlink.Text; } ));
if (textBoxValue == string.Empty)
Thread.Sleep(5000);
Reed is correct, but the reason you need to do this is that GUI elements are not thread safe and so all GUI operations have to be done on the GUI thread to ensure that the content is being read correctly. Its less obvious why this is necessary with a read operation like this but it is very necessary with writes and so the .NET framework just requires all access to the GUI to be done in the GUI thread.

Categories