Threading with listbox in C# [duplicate] - c#

This question already has answers here:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
(22 answers)
Closed 7 years ago.
i am developing a code in which a have to read the data form list box and upload an external file, press a button named Start and with this listbox i am getting an error as shown below.
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.Windows.Forms.dll
Additional information: Cross-thread operation not valid: Control
'listBox1' accessed from a thread other than the thread it was created
on.
my code is as follows
private void Start_Click(object sender, EventArgs e)
{
Thread ss = new Thread(Automode);
ss.Start();
}
private void Automode()
{
....
for (int i = 0; i < listBox1.Items.Count; i++)
{
listBox1.SetSelected(i, true);
string pattern = "[gxyzbcmij][-+]?[0-9]*\\.?[0-9]*";
string text = listBox1.Text;
Regex gcode = new Regex(pattern, RegexOptions.IgnoreCase);
MatchCollection code = gcode.Matches(text);
}
.....
}
here at listbox.SetSelected command it is giving an exception as shown above. please suggest the alternate ways to write it.

delegate void SetSelectedCall(int index, bool option);
private void SetSelectedElement(int index, bool option)
{
if (this.listBox1.InvokeRequired)
{
SetSelectedCall d = new SetSelectedCall(SetSelectedElement);
this.Invoke(d, new object[] { int index, bool option});
}
else
{
this.listBox1.SetSelected(index,option);
}
}
Taken from Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on and tailored for this question.

You can't access the listBox1 from a background thread.
If possible, run the code from the function Automode() directly in the Start_Click method. If you must have the code ran in a background thread, I would perhaps suggest something more like a Task, that way you can still perform the action based on passing arguments and awaiting a response. Then you can still listBox1 items as selected.

Related

Change the label content while processing [duplicate]

This question already has answers here:
Not updating GUI in time
(2 answers)
WinForm Application UI Hangs during Long-Running Operation
(3 answers)
Accessing UI controls in Task.Run with async/await on WinForms
(6 answers)
Closed 5 years ago.
I have a function which makes process. At the beginning of the function I want to change the text of a label which indicates the state, and once the process ends, change it again.
The fact is that only is shown the final change.
I know I can make a thread for the process but not needed in this case and I merely want to know if there's some tip or trick to accomplish it whitout the use of a thread.
In this case When you change something in UI it does not change until the whole process is completed so as you said you can only see the final state of your label. The trick is simple. You need to use a secondary thread while you are going to update the label for the fist time.
Look at the example below :
class Program
{
private delegate void del();
static void Main(string[] args)
{
del d = updateConsole;
var res = d.BeginInvoke(null, null);
while (!res.IsCompleted)
{
// do the job here
}
d.EndInvoke(res);
Thread.Sleep(1000);
Console.Clear();
Console.WriteLine("Done!");
Console.Read();
}
private static void updateConsole()
{
for (var i = 0; i <= 10; i++)
{
Thread.Sleep(500);
Console.Clear();
Console.WriteLine(i);
}
}
}
This simple technique helps you to separate the first update of the label from the whole process.

How to create thread safe GetEventHandler()? [duplicate]

This question already has answers here:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
(22 answers)
Closed 6 years ago.
public partial class JobDataDuplicatorForm : Form
{
public JobDataDuplicatorForm(IJobDataDuplicatorEngine engine)
{
_engine.CopyStartedEvent += GetEventHandler(OnCopyStarted);
_engine.CopyEndedEvent += GetEventHandler(OnCopyEnded);
...
}
private static EventHandler GetEventHandler(Action action)
{
return (sender, args) => action();
}
private void OnCopyStarted()
{
copyStatus.Text = "Copy progress: ";
generateButton.Enabled = false; // Cross-thread operation not valid
}
}
I have the following exception:
Additional information: Cross-thread operation not valid: Control
'generateButton' accessed from a thread other than the thread it was created on.
Can I fix the exception by changing GetEventHandler() instead of wrapping each button in different places like this
Invoke((MethodInvoker)delegate {
generateButton.Enabled = false;
}); ?
How can I do this?
From your comments you said you call JobDataDuplicatorForm(IJobDataDuplicatorEngine engine) from a background thread.
Your class is a Form, any windows controls (Which includes Form) must be initially created on the UI thread or things like Invoke and InvokeRequired break. Whatever code is calling the constructor of JobDataDuplicatorForm must do that call from the UI thread.

Increase progress bar each second -- error [duplicate]

This question already has answers here:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
(22 answers)
Closed 7 years ago.
it's my first experience with C#, I'm trying to make a progress bar that increases each second on a value (a part of program, it receives current value from another object and sets it to the progress bar).
My simplified object source:
public delegate void LoadingProgressChanged(int percents);
public event LoadingProgressChanged loadingProgressChanged;
public void Enable()
{
loadingTimer = new Timer(1000);
loadingTimer.Elapsed += new ElapsedEventHandler(IncreaseLoadingPercentage);
loadingTimer.Start();
}
private void IncreaseLoadingPercentage(object source, EventArgs e)
{
loadedPercents += getLoadingPercentsPerSecond();
loadingProgressChanged(loadedPercents);
}
Form sources:
In constructor
router.loadingProgressChanged += new AbstractRouter.LoadingProgressChanged(percentageChanged);
Body of percentageChanged
public void percentageChanged(int percs)
{
progressBar1.Value = percs;
}
And I get error
An exception of type 'System.InvalidOperationException' occurred in
System.Windows.Forms.dll but was not handled in user code
Additional information: Cross-thread operation not valid: Control
'progressBar1' accessed from a thread other than the thread it was
created on.
If there is a handler for this exception, the program may be safely
continued.
I understand why it happens: it seems that percentageChanged form is called in timer thread. But how to implement it correctly? Thanks!
Try with something like this:
public void percentageChanged(int percs)
{
Invoke(new Action(() =>
{
progressBar1.Value = percs;
}));
}

The calling thread cannot access this object because a different thread owns it" exception [duplicate]

This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 9 years ago.
Hi I am first time working on Threads not sure If I am doing correct
I am getting Error saying :
The calling thread cannot access this object because a different thread owns it" exception
private void ImportProductStatsButtonClick(object sender, EventArgs e)
{
// Get the currently selected manufacturer from the combo box
var selected = comboBoxCorporation.SelectedItem;
buttonProductStatsAndRetailerStats.Enabled = false;
buttonSummariseRetailerStats.Enabled = false;
buttonSummariseProductStats.Enabled = false;
// Do we have one?
if (selected != null)
{
// Extract the combo record
var corporation = (ComboBoxCorporrationItem)selected;
// Do we have one?
if (corporation.Corporation != null)
{
// yes
// Make this on a seperate thread so that the UI continues to work
var thread = new Thread(MigrateProductStats);
thread.Start(corporation.Corporation.Id); // This enables me to pick the manufacturer that we are summarizing for
}
}
}
private void MigrateProductStats(object corporationIdObj)
{
// after thread completion I need to Enable my buttons.
buttonProductStatsAndRetailerStats.Enabled = true;
buttonSummariseProductStats.Enabled = true;
}
Try with:
private void MigrateProductStats(object corporationIdObj)
{
Invoke(new Action(() =>
{
// after thread completion I need to Enable my buttons.
buttonProductStatsAndRetailerStats.Enabled = true;
buttonSummariseProductStats.Enabled = true;
});
}
Even better than Control.Invoke would be to use BackgroundWorker to handle threading for you. It generates progress and completion events back on the UI thread to make UI updates easy.
If you're using C# 5, you can also use async to start the background processing and await to cause the UI updates to occur when processing completes.

Threading & Cross Threading in C#.NET, How do I change ComboBox Data from another Thread?

I need to use threading in my app, but I don't know how to perform a cross threading operation.
I want to be able to change the text of a form object (in this case a Combo Box), from another thread, I get the error:
Cross-thread operation not valid: Control 'titlescomboBox' accessed from a thread other than the thread it was created on.
I don't really understand how to use the invoke and begin invoke functions, So im really looking for a dead simple example and explanation for this so I can learn around that.
Also any beginner tutorials would be great, I found a few, but their all so different, I don't understand exactly what I need to do to perform cross threading ops.
Here is the code:
// Main Thread. On click of the refresh button
private void refreshButton_Click(object sender, EventArgs e)
{
titlescomboBox.Items.Clear();
Thread t1 = new Thread(updateCombo);
t1.Start();
}
// This function updates the combo box with the rssData
private void updateCombo()
{
rssData = getRssData(channelTextBox.Text); // Getting the Data
for (int i = 0; i < rssData.GetLength(0); i++) // Output it
{
if (rssData[i, 0] != null)
{
// Cross-thread operation not valid: Control 'titlescomboBox'
// accessed from a thread other than the thread it was created on.
titlescomboBox.Items.Add(rssData[i, 0]); // Here I get an Error
}
titlescomboBox.SelectedIndex = 0;
}
}
I use the following helper class:
public static class ControlExtensions
{
public static void Invoke(this Control control, Action action)
{
if (control.InvokeRequired)
{
control.Invoke(new MethodInvoker(action), null);
}
else
{
action.Invoke();
}
}
}
Now you can call something like MyCombo.Invoke(() => { MyCombo.Items.Add(something); }) --- or any other control (such as the form) before the invoke since they are all created on the main thread.
The thing is that controls can only be accessed from the thread they were created on (the main application thread in this case).
HTH
This exception is thrown because of you are trying to access to a control members that is created on another thread. When using controls you should access the control members only from the thread that the control created on.
The control class helps you to know weather the control is no on the thread that is created on or not by providing InvokeRequeired property. so if 'control.InvokeRequeired' returns true that indicates that you are on a different thread. to help you out. Control support Invoke and BeginInvoke methods that will handle the execution of method to the control main thread. So:
If you are using 3.5 and above, I suggest you to use the extension method that Eben Roux show in his answer.
For 2.0:
// This function updates the combo box with the rssData
private void updateCombo()
{
MethodInvoker method = new MethodInvoker(delegate()
{
rssData = getRssData(channelTextBox.Text); // Getting the Data
for (int i = 0; i < rssData.GetLength(0); i++) // Output it
{
if (rssData[i, 0] != null)
{
// Cross-thread operation not valid: Control 'titlescomboBox'
// accessed from a thread other than the thread it was created on.
titlescomboBox.Items.Add(rssData[i, 0]); // Here I get an Error
}
titlescomboBox.SelectedIndex = 0;
}
});
if (titlescomboBox.InvokeRequired)//if true then we are not on the control thread
{
titlescomboBox.Invoke(method);//use invoke to handle execution of this delegate in main thread
}
else
{
method();//execute the operation directly because we are on the control thread.
}
}
if you use C# 2.0 this
Take a look at this What is the best way to update form controls from a worker thread? - it should resolve your issue.

Categories

Resources