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.
Related
This question already has answers here:
How do I create and show WPF windows on separate threads?
(4 answers)
The calling thread cannot access this object because a different thread owns it.WPF [duplicate]
(6 answers)
Closed 2 years ago.
I have an init method in which I create a thread and a window is displayed
This is my application code
public static SplashWindow _splashWindow;
private static ManualResetEvent ResetSplashCreated;
private static Thread SplashThread;
public static void Init(SplashWindow splashWindow)
{
_splashWindow = splashWindow;
ResetSplashCreated = new ManualResetEvent(false);
SplashThread = new Thread(() => ShowSplash(_splashWindow));
SplashThread.SetApartmentState(ApartmentState.STA);
SplashThread.IsBackground = true;
SplashThread.Name = "Splash Screen";
SplashThread.Start();
ResetSplashCreated.WaitOne();
}
public static void ShowSplash(SplashWindow splash)
{
splash.Show();
ResetSplashCreated.Set();
System.Windows.Threading.Dispatcher.Run();
}
now when i call this code:
SplashHelper.Init(new anim());
I get an error in the splash.show(); line
System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'
You cannot create the window on one thread and Show() it on another.
You will have to both create the thread and call Show() in your ShowSplash method (or on the calling thread).
If you look at the source code of Show, you'll see that the first thing it does is to call a VerifyContextAndObjectState() method.
This method checks whether you are on the thread on which the window was originally created. If you are on another thread, it throws the InvalidOperationException that you are currently getting.
This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(15 answers)
The calling thread cannot access this object because a different thread owns it.WPF [duplicate]
(6 answers)
Closed 2 years ago.
I have an application which has a C# front end (GUI client), and a C++ back end (business logic). The back end is responsible for requesting progress bar functionality and does this by issuing events which the front-end has observer delegates to respond to and act upon. so events are dispatched and responded to in the main thread.
I would like to spawn a second thread to display and update the progress bar, as the main thread is occupied by the back-end doing its thing. While I can show the progress bar window when supposed to, and correctly hide when finished, it will not respond to updates/increments.
ProgressBarWindow holds the progress bar control (pBar).
ProgressBarWindow is owned by progressBarThread.
public static EventObserver.ProgressBeginEvent pbe = null;
public static EventObserver.ProgressFinishEvent pfe = null;
public static EventObserver.ProgressIncrementEvent pie = null;
public static Thread progressBarThread = null;
static private void InitialiseProgressBarManager()
{
// Setup the progress bar callbacks...
pbe = new EventObserver.ProgressBeginEvent(delegate
(int currentIncrements, int totalIncrements, string message)
{
// Create the thread and progress bar window...
progressBarThread = new Thread(() =>
{
ProgressBarWindow sw = new ProgressBarWindow();
sw.pBar.IsIndeterminate = false;
sw.pBar.Minimum = currentIncrements.Value;
sw.pBar.Maximum = totalIncrements.Value;
sw.pBar.Value = 0;
sw.Show();
pie = new EventObserver.ProgressIncrementEvent(delegate ()
{
sw.pBar.Value++; // The calling thread cannot access this object... see below
});
pfe = new EventObserver.ProgressFinishEvent(delegate ()
{
progressBarThread.Abort();
progressBarThread = null;
});
});
progressBarThread.SetApartmentState(ApartmentState.STA);
progressBarThread.IsBackground = true;
progressBarThread.Start();
});
}
The window shows when expected, and the ProgressIncrementEvent gets raised correctly (it is owned by the thread), however I get an exception when it tries to access the value.
The calling thread cannot access this object because a different thread owns it.
Do I need a mutex or some other lock? I was hoping the scope of the observer delegate would allow the delegate to have mutable access to the thread local ProgressBarWindow even though it is being invoked from the main thread?
I'm not a great C# developer and even less so C# threading so I am a bit stuck about what I should be doing here or even if I can achieve this behaviour. Any help or direction to get this working would be appreciated.
P.S I am using WPF with ProgressBarWindow being defined in XAML.
Try to access the control using the window´s dispatcher:
sw.Dispatcher.BeginInvoke(new Action(() => sw.pBar.Value++));
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.
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;
}));
}
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.