Invoke methods in a thread - c#

I can't use eventArgs from a method trigged for a second Thread:
public class MovilinkCommunication
{
//Method Declarations
public delegate void MovilinkWatchParametersEventMethod(ParameterAddress sender, MovilinkEventArgs e);
private MovilinkWatchParametersEventMethod onWatchParameterMethod;
//class constructor
//here, the user inputs the method (in main thread) that desires to call in
//parameter changed moment
public MovilinkCommunication(MovilinkWatchParametersEventMethod userOnWatchParameterMethod)
{
//assign user method (in main thread) to wach variables
onWatchParameterMethod = userOnWatchParameterMethod;
//start communication thread (second thread)
Thread movilinkThread = new Thread(new ThreadStart(movilinkIOManagerThread));
movilinkThread.Start();
}
.
.
.
//create delegates with "sender" parameter and "e" conditions of call
delegate void CallOnWatchParameterMethod(ParameterAddress sender, MovilinkEventArgs e);
private void callOnWatchParameterMethod(ParameterAddress sender, MovilinkEventArgs e)
{
//calling user method in main thread with event args obtained in
//communication thread (second thread)
onWatchParameterMethod(sender, e);
}
.
.
.
//communication thread
private void movilinkIOManagerThread()
{
ParameterAddress sender;
MovilinkEventArgs e;
.
.
.
while (movilinkAccessor.OperationStatusOk)
{
.
.
.
CallOnWatchParameterMethod thdCallOnWatchParameterMethod =
new CallOnWatchParameterMethod(callOnWatchParameterMethod);
Dispatcher.CurrentDispatcher.Invoke(thdCallOnWatchParameterMethod, new object[] { sender, e });
.
.
.
}
}
}
Works fine, but when I try use "sender" and "e" event args in user method (in main thread), the message bellow appears:
"The calling thread cannot access this object because a different thread owns it."
Can someone give me a hint about this problem? Thanks,
Jeferson
Follow Tudor, thanks again. This code is in window.xaml.cs code. The code in first post is in MovilinkComunication.cs.
MovilinkCommunication comunicadorMovilink;
private void wndPrincipal_Loaded(object sender, RoutedEventArgs e)
{
//creating communication object, setting the desired event
//to be trigged in secundary thread
comunicadorMovilink =
new MovilinkCommunication(getChangeParameters_Movilink);
}
.
.
.
//desired method to made actions in window, if detected
//change of parameters in external hardware
private void getChangeParameters_Movilink(ParameterAddress sender, MovilinkEventArgs e)
{
//error occurs here. Any code with GUI return error.
label24.Content = e.ActualValue.ToString();
}

The label update needs to be done via Dispatcher.BeginInvoke:
private void getChangeParameters_Movilink(ParameterAddress sender, MovilinkEventArgs e)
{
label24.Dispatcher.BeginInvoke(
(Action)(() =>
{
label24.Content = e.ActualValue.ToString();
}));
}

if your application is winforms, you can do this
public void d()
{
if (this.InvokeRequired)
{
BeginInvoke( new MethodInvoker( delegate() {
foo(a, b);
} ) );
}
else
{
foo(a, b);
}
}
private void foo(int a, int b)
{
}
in this example, d and foo are located in the form's class

Thanks a lot, this works fine
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate()
{
printausfueren();
}));
}
else
{
printausfueren();
}

Related

BackgroundWorker: InvalidOperationException in RunWorkerCompleted

I have a WinForm with a backgroundWorker:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SeoTools.Utils;
namespace SeoTools.UI
{
public partial class UIProgress : Form
{
public UIProgress(DoWorkEventHandler doWorkEventHandler, RunWorkerCompletedEventHandler runWorkerCompletedEventHandler)
{
InitializeComponent();
this.backgroundWorker.WorkerReportsProgress = true;
this.backgroundWorker.WorkerSupportsCancellation = true;
this.backgroundWorker.DoWork += doWorkEventHandler;
this.backgroundWorker.RunWorkerCompleted += runWorkerCompletedEventHandler;
}
public void Start()
{
var foo = SynchronizationContext.Current;
backgroundWorker.RunWorkerAsync();
}
private void btnStop_Click(object sender, EventArgs e)
{
btnStop.Enabled = false;
btnStop.Text = "Stopping...";
backgroundWorker.CancelAsync();
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
try
{
wdgProgressBar.Value = e.ProgressPercentage;
if (this.Visible == false)
{
this.ShowDialog();
this.Update();
}
}
catch (InvalidOperationException) {}
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Hide(); //Here I get a InvalidOperationException
this.Dispose();
}
}
}
First time I run this it works fine. But second time I get InvalidOperationException when calling this.Hide().
"Additional information: Cross-thread operation not valid: Control 'UIProgress' accessed from a thread other than the thread it was created on."
The weird thing is on first run foo in Start() is a WindowsFormsSyncronizationContext but on the second try it's a System.Threading.SyncronizationContext.
The application I'm writing is a ExcelDna plugin.
EDIT
Start() is called like this:
UIProgress uiProgress = new UIProgress(
delegate(object sender, DoWorkEventArgs args)
{
....
},
delegate(object sender, RunWorkerCompletedEventArgs args)
{
...
}
);
uiProgress.Start();
Your Start() method must be called from code that runs on the UI thread to allow the BackgroundWorker to operate correctly. It was not when you get this exception. Add protective code to your method so you can diagnose this mishap:
public void Start()
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
throw new InvalidOperationException("Bug! Code called from a worker thread");
}
backgroundWorker.RunWorkerAsync();
}
Now you can set a breakpoint on the throw statement and use the debugger's Call Stack window to find out why this happened.
You are calling UI operation on background thread. This is the reason for that exception. I would use entirely different method to make the progress form the best one is to use Task with IProgress. The other way it to use this:
private void backgroundWorker_ProgressChanged( object sender , ProgressChangedEventArgs e )
{
this.UpdateOnMainThread(
( ) =>
{
wdgProgressBar.Value = e.ProgressPercentage;
if ( this.Visible == false )
{
this.ShowDialog( );
this.Update( );
}
} );
}
private void UpdateOnMainThread( Action action )
{
if ( this.InvokeRequired )
{
this.BeginInvoke( ( MethodInvoker ) action.Invoke);
}
else
{
action.Invoke( );
}
}
private void backgroundWorker_RunWorkerCompleted( object sender , RunWorkerCompletedEventArgs e )
{
this.UpdateOnMainThread(
( ) =>
{
this.Hide( ); //Here I get a InvalidOperationException
this.Dispose( );
} );
}
Use the BeginInvoke() method on the form:
//http://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.BeginInvoke(new InvokeDelegate(InvokeMethod));
}
public delegate void InvokeDelegate();
public void InvokeMethod()
{
this.Hide();
this.Dispose();
}
I think you can find some help here: BackgroundWorker hide form window upon completion .
However don't forget to detach BackgroundWorker events and stop BackgroundWorker it self like explained in here: Proper way to Dispose of a BackGroundWorker .
The problem can be in the
this.Dispose();
in the backgroundWorker_RunWorkerCompleted event. With that you are disposing form page. Is that what you want to do? Or you want to dispose BackgroundWorker? Disposing form page all resources are released so doing this.Hide(); a second time can be a mistake.
For more info, you can see this links: C# Form.Close vs Form.Dispose and Form.Dispose Method
You must check this link
How to update the GUI from another thread in C#?
Probably have all the possible answers
Hope this Help
You're running a call to the main thread from a thread that can't manipulate UI.
The simplest way is to use anonymous delegate invoke.
Change this:
if (this.Visible == false)
{
this.ShowDialog();
this.Update();
}
For this:
this.Invoke((MethodInvoker) delegate {
if (this.Visible == false)
{
this.ShowDialog();
this.Update();
}
});
It's not the most optimized way but does the job awesomely fast without much recode. :)

Events Fired in Background Thread Ignored

I'm running a C# forms application which starts a thread to acquire some data. This thread has some events inside it i.e: the events fire in the thread and are supposed to be captured by the same thread. However, the thread's events don't seem to be firing. Any clues?
private void btnPlay_Click(object sender, EventArgs e)
{
Thread thread = new Thread(kinect.onlineRun);
thread.IsBackground = true;
thread.Start();
}
inside the thread:
void PointCreated(object sender, IdEventArgs e) // a certain event that should fire and it doesn't
{
Console.WriteLine("Event Fired!");
}
public void onlinerun()
{
Console.WriteLine("run started"); // this is printed on console
while (true)
{
do_some_work();
//this work could result in the PointCreated event firing
}
}
Give something like this a try:
Assuming your calling class is called Controller and your delegate is called ControlEventHandler...
private void PointCreated(object sender, IdEventArgs e)
{
// Ensure the event was received in the calling thread
if (this.InvokeRequired)
{
if (e != null)
{
// We aren't in the correct thread so pass on the event
this.BeginInvoke(new Controller.ControllerEventHandler(this.PointCreated), new object[] { sender, e });
}
}
else
{
lock (this)
{
Console.WriteLine("Event Fired!");
// TODO: Do some stuff here
}
}
}

updating gui from another class c#

hey i am new to c# plz help.
i am writing a program that sorts data in a file and it is a time consuming process so i thought that i should run it in a separate thread and since it has alot of step so i made a new class for it. the problem is that i want to show the progress in the main GUI and i know for that i have to use Invoke function but the problem is that the form control variables are not accessible it this class. what should i do ??????
sample code:
public class Sorter
{
private string _path;
public Sorter(string path)
{
_path = path;
}
public void StartSort()
{
try
{
processFiles(_path, "h4x0r"); // Just kidding
}
catch (Exception e)
{
MessageBox.Show("Error: " + e.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void processFiles(string Dir, string[] key)
{
/* sorting program */
}
and it is used as
public partial class Form1 : Form
{
Sorter sort;
public Form1()
{
InitializeComponent();
}
private void browseBtn_Click(object sender, EventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
textBox1.Text = folderBrowserDialog1.SelectedPath;
}
private void startBtn_Click(object sender, EventArgs e)
{
if (startBtn.Text == "Start Sorting")
{
Thread worker = new Thread(new ThreadStart(delegate() {
sort = new Sorter(textBox1.Text);
sort.StartSort(); }));
worker.start();
}
else
MessageBox.Show("Cancel");//TODO: add cancelling code here
}
}
plz help..
Add an Event to your class that is doing the multi-threaded work, that triggers when the progress changes. Have your form subscribe to this event and update the progress bar.
Note ProgressEventArgs is a little class that inherits EventArgs and has an Integer for the progress.
// delegate to update progress
public delegate void ProgressChangedEventHandler(Object sender, ProgressEventArgs e);
// Event added to your worker class.
public event ProgressChangedEventHandler ProgressUpdateEvent
// Method to raise the event
public void UpdateProgress(object sender, ProgressEventArgs e)
{
ProgressChangedEventHandler handler;
lock (progressUpdateEventLock)
{
handler = progressUpdateEvent;
}
if (handler != null)
handler(sender, e);
}
I would recommend you read up on the BackgroundWorker class. It is exactly for the problem you are trying to solve and makes things a lot easier than doing manual threading yourself.
Brief Example
public Form1()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
}
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void btnStart_Click(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i < 101; ++i)
{
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
break;
}
else
{
//Sort Logic is in here.
Thread.Sleep(250);
backgroundWorker.ReportProgress(i);
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy && backgroundWorker.WorkerSupportsCancellation)
backgroundWorker.CancelAsync();
}
You could do something like this:
public delegate void StatusReporter(double progressPercentage);
public class MainClass
{
public void MainMethod()
{
Worker worker = new Worker(ReportProgress);
ThreadStart start = worker.DoWork;
Thread workThread = new Thread(start);
workThread.Start();
}
private void ReportProgress(double progressPercentage)
{
//Report here!!!
}
}
public class Worker
{
private readonly StatusReporter _reportProgress;
public Worker(StatusReporter reportProgress)
{
_reportProgress = reportProgress;
}
public void DoWork()
{
for (int i = 0; i < 100; i++ )
{
// WORK, WORK, WORK
_reportProgress(i);
}
}
}
There are a few option available to solve this sort of issue. In any case, you will have to fiddle with Invoke to get the UI to update.
You could...
...add an event that fires on your new class which your UI can listen to, and Invoke as applicable - you'd still need to pass the data to your worker class (by constructor, properties, method call, etc)
...keep the method as a method on your form, and pas that to start your new thread from (after all, a new thread doesn't have to be starting in a different class)
...change the access modifiers on your controls to be (say) internal such that any class within the same assembly can Invoke changes to the controls, or read from them.
...make your worker class a child of the form it needs to access - it can then see the privates of its parent, as long as it is passed a reference to the instance.

Pattern to handle threads status in C#

I am currently developing a program that must handle multiple threads. When I start the program I run multiple threads (my example is limited to one). I have to display their status in a single TextBox. I opted for the next solution. Is this way is correct? Are there any other pattern? The Observer perhaps? I can't find a good way to do this on the web.
namespace ThreadTest
{
public partial class Form1 : Form
{
// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void ChangedCallback(object sender, JobEventArgs e);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MyThread myThread = new MyThread();
myThread.Changed += new MyThread.JobEventHandler(myThread_Changed);
// Create the thread object, passing in the Alpha.Beta method
// via a ThreadStart delegate. This does not start the thread.
Thread oThread = new Thread(new ThreadStart(myThread.MyJob));
// Start the thread
oThread.Start();
}
void myThread_Changed(object sender, JobEventArgs e)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
ChangedCallback d = new ChangedCallback(myThread_Changed);
this.Invoke(d, new object[] { sender, e });
}
else
{
// Display the status of my thread
textBox1.Text += e.Counter;
}
}
}
public class MyThread
{
// A delegate type for hooking up change notifications.
public delegate void JobEventHandler(object sender, JobEventArgs e);
// An event that clients can use to be notified whenever the
// elements of the list change.
public event JobEventHandler Changed;
// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(JobEventArgs e)
{
if (Changed != null)
Changed(this, e);
}
public void MyJob()
{
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(1000);
JobEventArgs e = new JobEventArgs(i);
OnChanged(e);
}
}
}
public class JobEventArgs
{
public int Counter { get; set; }
public JobEventArgs(int i)
{
Counter = i;
}
}
}
It looks just fine to me. In fact you are using the observer pattern. It's just c#'s nice event syntax eliminating the interface and reducing boilerplate.
However, there is a lot of redundant code and other readability problems in there.
The this qualifier is redundant when specifying a memeber such as this.textBox1 or this.Invoke(...).
Try to always specify visibility such as private or public for methods.
A suitable delegate is created automatically around a method-group enabling a shorthand syntax. For example: new Thread(myThread.MyJob) or myThread.Changed += myThread_Changed.
Consider using simple Action as event handler delegate types instead of a custom (ChangedCallback). The myThread_Changed method can then just accept an int as single parameter allowing you to drop lots of redundant types.
To avoid problems make a thread-local copy of the event before checking for null and invoking.
Like this:
JobEventHandler tmp = Changed;
if (tmp != null) tmp(this, e);
You code is not fine.
Why do you not let your thread class create the thread? It's more logical and gives a nice encapsulation:
You should not declare delegates inside a class, it makes refactoring harder.
If you are sleeping in the thread, why don't you use a Timer instead?
#
public partial class Form1
{
delegate void ChangedCallback(object sender, JobEventArgs e);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MyThread myThread = new MyThread();
myThread.Changed += myThread_Changed;
myThread.Start();
}
void myThread_Changed(object sender, JobEventArgs e)
{
if (this.textBox1.InvokeRequired)
{
ChangedCallback d = new ChangedCallback(myThread_Changed);
this.Invoke(d, new object[] { sender, e });
}
else
{
textBox1.Text += e.Counter;
}
}
}
public class MyThread
{
private Thread _thread;
public MyThread()
{
_thread = new Thread(WorkerFunc);
}
public void Start()
{
_thread.Start();
}
// use the = {} pattern since you are using multithreading.
public event JobEventHandler Changed = {};
protected virtual void OnChanged(JobEventArgs e)
{
Changed(this, e);
}
private void WorkerFunc()
{
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(1000);
JobEventArgs e = new JobEventArgs(i);
OnChanged(e);
}
}
// A delegate type for hooking up change notifications.
public delegate void JobEventHandler(object sender, JobEventArgs e);

cross thread call

using System;
using System.Windows.Forms;
using agsXMPP;
using System.Text;
namespace iTalk2
{
public partial class Main : Form
{
agsXMPP.XmppClientConnection objXmpp;
public Main()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Console.WriteLine("Logging in. Please wait...");
Console.ReadLine();
objXmpp = new agsXMPP.XmppClientConnection();
agsXMPP.Jid jid = null;
jid = new agsXMPP.Jid("username" + "#gmail.com");
objXmpp.Password = "password";
objXmpp.Username = jid.User;
objXmpp.Server = jid.Server;
objXmpp.AutoResolveConnectServer = true;
try
{
objXmpp.OnMessage += messageReceived;
objXmpp.OnAuthError += loginFailed;
objXmpp.OnLogin += loggedIn;
objXmpp.Open();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
private void messageReceived(object sender, agsXMPP.protocol.client.Message msg)
{
string[] chatMessage = null;
chatMessage = msg.From.ToString().Split('/');
agsXMPP.Jid jid = null;
jid = new agsXMPP.Jid(chatMessage[0]);
agsXMPP.protocol.client.Message autoReply = null;
autoReply = new agsXMPP.protocol.client.Message(jid, agsXMPP.protocol.client.MessageType.chat, "This is a test");
objXmpp.Send(autoReply);
}
private void loginFailed(object o, agsXMPP.Xml.Dom.Element el)
{
Console.WriteLine("Login failed. Please check your details.");
}
private void loggedIn(object o)
{
Console.WriteLine("Logged in and Active.");
lblStatus.Text = "Online";
}
private void txtUsername_TextChanged(object sender, EventArgs e)
{
}
private void label1_Click(object sender, EventArgs e)
{
}
private void label2_Click(object sender, EventArgs e)
{
}
private void txtPassword_TextChanged(object sender, EventArgs e)
{
}
private void btnlogin_Click(object sender, EventArgs e)
{
}
}
}
This code is not working. the function 'loggedIn(object o)' is not working. it says the lblStatus (which is a label) is on another thread. the error window says "Cross-thread operation not valid: Control 'lblStatus' accessed from a thread other than the thread it was created on." thanks in advance.
You need to invoke a call on the UI thread. If you add code as follows at the top of the loggedIn method it should work:-
if(InvokeRequired)
{
Invoke(new Action<object>(loggedIn), o);
return;
}
WinForms is designed such that controls must only be manipulated on the UI-thread, the thread that runs the message-loop that manages the control.
Try this instead:
private void loggedIn(object o)
{
Console.WriteLine("Logged in and Active.");
Action act = () => lblStatus.Text = "Online";
Invoke(act);
}
If your application is such that this method can be called on the UI thread or a separate worker thread, you'd be better off testing forInvokeRequired(simply: am I on the control's UI thread?) and dealing with the result appropriately. For example,
private void loggedIn(object o)
{
if(InvokeRequired)
Invoke(new Action<object>(loggedIn), o);
else
{
Console.WriteLine("Logged in and Active.");
lblStatus.Text = "Online";
}
}
Note that Invokewill block until the UI-update is completed. If you want something more fire-and-forget, use BeginInvokeinstead.
When you start an application it is running from a single thread. This is the main thread, sometimes called the UI thread (since the UI will usually be rendered at startup and as a consequence it will be on that main thread.
Now, when you listen to events, your methods/delegates will get called from new threads. This is a consequence of the event based design. Normally this is not a problem unless you are trying to share data between two threads. This is exactly what happens with your UI elements. In this case your UI elements were created by your first thread but other threads are trying to update its value.
Given your design, you should check for IsInvokeRequired on the control and if so, use Invoke to set the new value. This will marshal your call from the new thread into the main thread that your UI is running on and will allow you to safely change the control.

Categories