The calling thread cannot access this object - Timer [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)
How to deal with cross-thread access exceptions?
(3 answers)
Closed 9 years ago.
I am setting up a Timer within a method with an interval of 1000 so that every second it will type another corresponding character into a Textbox (pretty much automating typing). When I check for _currentTextLength == _text.Length I get the threading error "The calling thread cannot access this object because a different thread owns it."
public void WriteText(string Text)
{
timer = new Timer();
try
{
_text = Text;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed_WriteText);
timer.Interval = 1000;
timer.Enabled = true;
timer.Start();
}
catch
{
MessageBox.Show("WriteText timer could not be started.");
}
}
// Write Text Timer Event
void timer_Elapsed_WriteText(object sender, ElapsedEventArgs e)
{
TextBoxAutomationPeer peer = new TextBoxAutomationPeer(_textBox);
IValueProvider valueProvider = peer.GetPattern(PatternInterface.Value) as IValueProvider;
valueProvider.SetValue(_text.Substring(0, _currentTextLength));
if (_currentTextLength == _text.Length) // Error here
{
timer.Stop();
timer = null;
return;
}
_currentTextLength++;
}
The variable _text is a private class variable and so is _currentTextLength. _textBox is self explanatory.
Any way to solve this?

Use a DispatcherTimer instead of a Timer.
A timer that is integrated into the Dispatcher queue which is
processed at a specified interval of time and at a specified priority.
Should solve your problem.

this simply means that you are trying to access some UI element from a thread other then it was created on. To overcome this you need to access it like this
this.Dispatcher.Invoke((Action)(() =>
{
//access it here
}));
Note: If you want to check whether you can access it normally or not you can use this
Dispatcher.CheckAccess

Related

Why am i getting this error: "The calling thread must be STA, because many UI components require this"? [duplicate]

This question already has an answer here:
Calling Thread must be STA
(1 answer)
Closed 6 years ago.
My goal is to show a notification ballon in 5 seconds. I am using Hardcodet.NotifyIcon.Wpf Library and following this tutorial
Demo Code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
new Timer(_ => ShowBallon(), null, 0, 1000 * 5);
}
private void ShowBallon()
{
string title = "WPF NotifyIcon";
string text = "This is a standard balloon";
new TaskbarIcon().ShowBalloonTip(title, text, BalloonIcon.None); //Error is thrown in this line
}
}
Error Message
You get this exception because the Timer callback is executed in a thread pool thread that doesn't have ApartmentState.STA, which is required for creating WPF UI elements.
Better use the DispatcherTimer class, which has a Tick event that is fired in the UI thread.
Use it like shown below for a single shot action. If you actually intended to execute the Tick handler periodically, just remove the Stop() statement.
public MainWindow()
{
InitializeComponent();
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(5) };
timer.Tick += ShowBallon;
timer.Start();
}
private void ShowBallon(object sender, EventArgs e)
{
((DispatcherTimer)sender).Stop();
string title = "WPF NotifyIcon";
string text = "This is a standard balloon";
new TaskbarIcon().ShowBalloonTip(title, text, BalloonIcon.None);
}

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.

C# Background worker: exception when Close() is called [duplicate]

This question already has answers here:
How to stop BackgroundWorker on Form's Closing event?
(12 answers)
Closed 9 years ago.
I have two background workers in my application that fill up a table and send log messages. They transmit these data using the "userState" of the ReportProgress method.
They are connected to the main thread through:
msg_worker.DoWork += message_worker_task;
msg_worker.ProgressChanged += msg_worker_ProgressChanged;
msg_worker.RunWorkerCompleted += worker_completed;
data_worker.DoWork += data_worker_task;
data_worker.ProgressChanged += data_worker_ProgressChanged;
data_worker.RunWorkerCompleted += worker_completed;
They are synchronized using two EventWaitHandle items that they set at the end of their doWork task:
private void message_worker_task(object sender, DoWorkEventArgs e)
{
try
{
while( .. ){
// do work
bw.ReportProgress( 10, new String("my message to append"));
}
}
finally
{
e.Result = 0;
msg_done.Set(); // EventWaitHandle
}
}
The Progress changed delegates insert data/log in the components that are visible to the user.
Now, the problem is that when I click on the Quit button in my UI, I wait on those 2 threads like this:
private void wait_threads()
{
int timeout = 30000;
Cursor.Current = Cursors.WaitCursor;
if (data_worker.IsBusy && !data_worker.CancellationPending)
{
data_worker.CancelAsync();
data_done.WaitOne(timeout);
}
if (msg_worker.IsBusy && !msg_worker.CancellationPending)
{
msg_worker.CancelAsync();
msg_done.WaitOne(timeout);
}
Cursor.Current = Cursors.Default;
}
This seems to be working (I use it at other places in the code), but in this "quitting" case, I have an exception raised, saying that I tried to insert data into the log component I have. This component is manipulated by the RunWorkerCompleted delegate.
The code which gets executed when Quit is clicked is this:
private void quit_Click(object sender, EventArgs e)
{
wait_threads(); // blocks until threads are finished
Close();
}
I think I figured out that while waiting for the threads to complete, they send a last event: the RunWorkerCompleted.
The problem is that I'm in the process of Close() 'ing my form, which means the form is not in a correct state.
What's more, if I check the e.Cancelled flag in the worker_completed function, I see it as false...
What can I do to make sure the RunWorkerCompleted is handled before my Close() function gets executed? (or rather, is not handled at all, because we're quitting).
I think you can check the property Cancellation Pending before calling ReportProgress.
while( .. ){
if (!bw.CancellationPending)
bw.ReportProgress( 10, new String("my message to append"));
}

thread and event [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
WPF access GUI from other thread
Good day ,
I write class
public class Metric1
{
public event MetricUnitEventHandler OnUnitRead;
public void ReiseEventOnUnitRead(string MetricUnitKey)
{
if (OnUnitRead!=null)
OnUnitRead(this,new MetricUnitEventArgs(MetricUnitKey));
}
.....
}
Metric1 m1 = new Metric1();
m1.OnUnitRead += new MetricUnitEventHandler(m1_OnUnitRead);
void m1_OnUnitRead(object sender, MetricUnitEventArgs e)
{
MetricUnits.Add(((Metric1)sender));
lstMetricUnit.ItemsSource = null;
lstMetricUnit.ItemsSource = MetricUnits;
}
Then i start new thread that every minute calls m1's ReiseEventOnUnitRead method.
In row lstMetricUnit.ItemsSource = null; throws excepition - "The calling thread cannot access this object because a different thread owns it." Why?
You cannot change GUI item from another thread that isn't the GUI thread,
If you are working with WinForms use Invoke and InvokeRequired.
if (lstMetricUnit.InvokeRequired)
{
// Execute the specified delegate on the thread that owns
// 'lstMetricUnit' control's underlying window handle.
lstMetricUnit.Invoke(lstMetricUnit.myDelegate);
}
else
{
lstMetricUnit.ItemsSource = null;
lstMetricUnit.ItemsSource = MetricUnits;
}
If you are working with WPF use Dispatcher.
lstMetricUnit.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
lstMetricUnit.ItemsSource = null;
lstMetricUnit.ItemsSource = MetricUnits;
}
));
You should use Dispatcher.
Example:
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => {
lstMetricUnit.ItemsSource = null;
lstMetricUnit.ItemsSource = MetricUnits;
})));
In WPF and Forms -> you cannot modify UI controls from different thread.

Categories

Resources