calling event that implements at other thread in C# - c#

I have a class with a Socket, listens to clients to receive data. When receive new data I want to call an event (if implemented) but as you know every connection has its own thread so the event will run at that thread and you know the rest. you can not work with form controls.
How do I call the event (or invoke it). I'm really new to thread and network programing so I appreciate any example.
public class HVremotechooser
{
public delegate void NewOrder(Order order);
public event NewOrder nOrder;
//... (code elided)
public void ReceiveCallback(IAsyncResult AsyncCall) // new connection of client
{
//... (code elided)
if (nOrder != null)
nOrder(Order); // calling the event "nOrder"
//... (code elided)
}
}
thank you.

If you want to update your form from a non-UI thread, you have to invoke the action. What I normally do is the following:
private void LongRunningBackgroundThread() {
// lots of work
...
// Update my form
InvokeIfRequired(() => {
...update form...
}
}
private static void InvokeIfRequired(Action a) {
if (control.InvokeRequired) {
control.Invoke(a);
} else {
a();
}
}
See here and here

I ran into a similar problem with a Silverlight application that I was working on last week, and used the Dispatcher.BeginInvoke method. With Windows forms, it looks like it might be easier to use Control.BeginInvoke instead (although I believe that either should work): http://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke.aspx

You can use the typical marshling operations like Invoke or BeginInvoke to inject the execution of a delegate onto the UI thread. Just pass an instance of ISynchronizeInvoke or SynchronizationContext to your class to facilitate the marshaling.
However, I would not do that in your case. Since, presumably anyway, these callbacks are occuring because of socket events it is possible likely they are coming in hard and heavy. You definitely do not want to slam your UI thread with all of that activity. Instead, package up all of the pertinent data and put into a collection that the UI thread can then poll for using a System.Windows.Forms.Timer on a more reasonable interval.
I rip on these marshling operations all of the time. They are way overrated and overused. Remember, there are two general methods of sharing data and signaling between UI and worker threads.
Push method via Invoke or BeginInvoke in the worker thread
Pull method via System.Windows.Forms.Timer in the UI thread
The pull method can be, and often is, more elegant.

UI Threading is a UI concern. In my opinion you shouldn't worry about invoking to the ui thread in this code. Rather the consumer of the event should do the Invoke or whatever other threading stuff they happen to need to do. That way if the UI person needs to change their strategy (e.g. by using a timer) your non-UI related code wont need to change.

Related

Delegate method not being run on UI thread

I am building an Windows Form-based app that listens on a port and when it receives a specific command, it opens a window (Form) that requests input.
My problem is that even though I am using a delegated method to open the window, only the window furniture/border is drawn. The contents of the form are not rendered at all.
From searching other answers on S.O., there seem to be two causes for this:
InitializeComponent() not being called
Trying to open the window from a non-UI thread
It appears that #2 is my problem. When I compare the ManagedThreadId in the form constructor and from the callback delegate, they are different.
As far as I can tell from the docs, the delegate should ensure that the callback is run on the UI thread.
Can anyone suggest why it isn't?
Below is a simplified version of what my code looks like.
The form
public wPrompt(bool silent, bool listen)
{
InitializeComponent();
// Thread.CurrentThread.ManagedThreadId returns 1
// Register a handler for scan requests received via the network
SocketListener.OpenFormRequest += OpenFormCommandHandler;
// Class that contains the code to open a socket and listen for commands
SocketListener.StartListening();
}
private void wPrompt_Load(object sender, System.EventArgs e)
{
// Thread.CurrentThread.ManagedThreadId returns 3
}
// The callback that gets called by the delegate
private void OpenFormCommandHandler()
{
// Thread.CurrentThread.ManagedThreadId returns 3
// Open the form
Visible = true;
}
The SocketListener class
class SocketListener
{
public delegate void OpenFormRequestEventHandler();
public static event OpenFormRequestEventHandler OpenFormRequest;
public static void StartListening()
{
// Thread.CurrentThread.ManagedThreadId returns 1
// Initialise and start worker thread
workerThread = new Thread(new ThreadStart(ListenThread));
workerThread.Start();
}
// A slightly modified version of the Synchronous Server Socket Example at
// https://learn.microsoft.com/en-us/dotnet/framework/network-programming/synchronous-server-socket-example
private static void ListenThread()
{
// Thread.CurrentThread.ManagedThreadId returns 3
// Opens socket and listens for command
if (/* command received */) {
OpenFormRequest?.Invoke();
}
}
}
The delegate callback function is run on the same thread as the socket listener. Not the UI thread as expected.
Can anyone explain what's happening please? I don't do a lot of .net development, so I am having trouble nutting this out.
As far as I can tell from the docs, the delegate should ensure that the callback is run on the UI thread. Can anyone suggest why it isn't?
There are no docs that should suggest that. I.e. it's not sufficient simply to use a delegate. You have to invoke the delegate using a mechanism that would move that invocation onto the UI thread, and there's nothing like that in the code you posted above. You seem to have misunderstood whatever it was that you read.
The issue with your code is that you appear to have confused the compiler-generated Invoke() method for a delegate with the framework-provided Control.Invoke() method. Your code calls the former, while you should be calling the latter. All that the former does is to actually invoke the delegate; the latter is what handles marshaling the execution of a delegate onto the UI thread so it can be executed there.
Frankly, it's a mistake for the socket-related code to try to address this at all. In the ListenThread() method, just raise the event normally (which ironically is the syntax you're using, so actually you don't need to change anything there). In your OpenFormCommandHandler() method, then you should call the Control.Invoke() method to execute whatever code you need to execute there, such as creating and showing a new form.
Based on your recent edit, in theory here is how you would change your event handler:
private void OpenFormCommandHandler()
{
// Thread.CurrentThread.ManagedThreadId returns 3
// Open the form
this.Invoke((MethodInvoker)(() => Visible = true;));
}
But I infer from your problem description that the form has not actually been shown once yet, which means it hasn't yet been tied to main thread and so Control.Invoke() is unlikely to work (you'd probably get an exception reporting that the window handle hadn't been created yet…I forget the exact wording, and it's not important enough for me to go looking it up right now).
Assuming that's the case, you need to get a synchronization context from elsewhere. Unfortunately, the question still lacks the specifics that would allow a more explicit answer showing exactly how to do that. But depending on what else is going on in your program, you could:
Pass a different Form instance to the wPrompt constructor and use that instance when calling Invoke(). Or,
Pass SynchronizationContext.Current to the wPrompt constructor, and call that object's Send() or Post() method (equivalent to Control.Invoke() and Control.BeginInvoke(), respectively).
There are other mechanisms you could use to capture and then use the synchronization context, but I'd say based on the details in your question, one of those two will be preferable to you.

Making C# callbacks between different threads

I working on a WPF GUI app that acts as socket server by using TcpListener class. TcpListener is configured to make an callback when data is received to the listened socket. However the problem is that TcpListener callback comes from another thread and causes following error when I try to touch GUI from the callback:
"Cross-thread operation not valid: Control 'slider' accessed from a thread other than the thread it was created on."
Any ideas how to solve this?
I'm familiar with Qt where this would be done with signal/slot system that can send events to another threads. Is there similar functionality in C#?
You should invoke your code in UI thread. Try to use Dispatcher
Application.Current.Dispatcher.Invoke(Callback):
You need to use the WPF Dispatcher class to invoke the method back to the UI thread - see
this
You want to use the Dispatcher.Invoke method.
If your this is DependencyObject class, you can simply use this:
this.Dispatcher.Invoke((Action)(() =>
{
slider.DoAnythingYouWant();
}));
You cannot directly access GUI elements from a separate (e.g. pulled from the thread pool for async operations or directly created with the Thread class). What you need to do is perform your action through the dispatcher, like so:
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() => slider.Text = "mystuff"));
For more information on how the Dispatcher manages threading, see the MSDN link below:
http://msdn.microsoft.com/en-us/library/vstudio/system.windows.threading.dispatcher
Found the solution to make callback function completely in UI thread (CommandHandler is method in MainForm and called from another thread from AsynchronousSocketListener):
void CommandHandler()
{
if (InvokeRequired)
{
/* If called from a different thread, we must use the Invoke method to marshal the call to the proper thread. */
BeginInvoke(new AsynchronousSocketListener.ReadHandler(CommandHandler));
return;
}
else
{
//do UI thread code here
}
}
For those may need working example, stuff was done this way in Basler Pylon 4.0 library example program named PylonLiveView.

Writing a method that reports progress

I'm writing a class that performs a certain operation in a library. But the operation is tedious, and I want to be able to find out the progress of the method inside that class so that I can use it in a WinForms application to report the progress.
I'm planning to run my class on another thread in my WinForms application and I want the class to be separated from the concerns of the WinForms application, and I don't want to bind it to anything specific other than what it does.
What would be the best way to implement a progress reporting mechanism in a library class?
Would it be a good idea to somehow have a progress variable in the class, and add an event listener to it in my WinForms application? And if it is, how can I do it?
Edit: I have used the BackgroundWorker class before, but my problem is I don't want my library class to be concerned with any of the multithreading operations. So I don't want to invoke ReportProgress in the library class, I want to (maybe) have a variable in the class that contains the current progress and I want the UI thread to somehow "subscribe" to it. I don't know if that's a good way to design it though.
Look into the BackgroundWorker class. It supports automatic marshaling across threads for progress reporting, and it has a very simple event model for this kind of support.
Edit: Given your position on using BackgroundWorker directly, what you might do is create a simple wrapper:
// Error checking elided for expository purposes.
public interface IProgressReporter
{
void ReportProgress(int progress, object status);
}
public class BackgroundWorkerProgressReporter : IProgressReporter
{
private BackgroundWorker _worker;
public BackgroundWorkerProgressReporter(BackgroundWorker worker)
{
_worker = worker;
}
public void ReportProgress(int progress, object status)
{
_worker.ReportProgress(progress, status);
}
}
Then, alter the constructor (or add a property) of the class that you want to report progress to accept an IProgressReporter. This is a form of dependency injection, and should meaningfully allow your object to report progress whilst also avoiding specific dependencies on threading libraries.
Here you can do 2 different ways I will post both options below to help point you in the right direction
You should be doing this on another thread, and then updating your UI thread from that thread. You are blocking further processing by performing this work on the UI thread.
If you can't move this code to the UI thread, then you could always call Application.DoEvents, but I strongly suggest you explore these options first:
System.ComponentModel.BackgroundWorker
System.Threading.ThreadPool
System.Threading.Thread
System.Threading.Tasks namespace
Second Alternative you could do something like this:
You'll need to get your data from one thread to the other. This can be done a couple ways...
First, your "background" thread could update some kind of "CurrentStatus" string variable that it changes as it goes along. You could then put a timer on your form that would then grab the CurrentStatus variable and update the label with it.
Second, you could simply invoke the operation from the background thread to the UI thread with a delegate using the InvokeRequired property of the label control. So for example...
private delegate void UpdateStatusDelegate(string status);
private void UpdateStatus(string status)
{
if (this.label1.InvokeRequired)
{
this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
return;
}
this.label1.Text = status;
}
You can call that UpdateStatus() method from any thread (UI or background) and it will detect whether or not it needs to invoke the operation on the main UI thread (and if so, does it).
Edit: To actually set up the thread, you can do so like this:
private void StartProcessing()
{
System.Threading.Thread procThread = new System.Threading.Thread(this.Process);
procThread.Start();
}
private void Process() // this is the actual method of the thread
{
foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
// Do processing
// Show progress bar
// Update Label on Form, "f.Name is done processing, now processing..."
UpdateStatus("Processing " + f.Name + "...");
}
}
Then when the user clicks the "GO" button you'll simply call StartProcessing().

Custom Events and Threading

I have two different projects and in one, I have a class that defines a custom event to fire under certain conditions:
public delegate void ButtonHandler(object myObject,
GuitarArgs myargs);
public event ButtonHandler OnButtonPress;
... other stuff ...
GuitarArgs myArgs = new GuitarArgs( guitarState );
if(OnButtonPress!= null)
OnButtonPress(this, myArgs);
Then in another project I create an instance of this class and subscribe to this event:
Guitar.OnButtonPress += Guitar_OnButtonPress;
The event then fires properly, but it seems to be on a different thread, because when I try to access some UI elements, I get an error : The calling thread cannot access this object because a different thread owns it.
The code throwing the error is:
void Guitar_OnButtonPress(object myObject, Guitar.GuitarArgs myargs)
{
GuitarCheck(myargs.State);
}
private void GuitarCheck(GuitarState getState)
{
if (getState.green)
{
VisualTreeHelper.HitTest(guitarCanvas, null,
MyHitTestResult,
new GeometryHitTestParameters(
new RectangleGeometry(new Rect(1, 411, 88, 78))));
}
}
What can I do to make this run?
Thank you.
You need to check if your event handler is running on a non-UI thread and, if so, invoke it on the UI thread:
How to update the GUI from another thread in C#?
I would like to highlight the less-upvoted answer, which provides a very elegant approach using an extension method. I use this in all of my WinForms projects (and use a variant in WPF/Silverlight projects)
https://stackoverflow.com/a/3588137/141172
If you are using WinForms
this.Invoke(() => GuitarCheck(myargs.State));
(http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx)
If you are using WPF
this.Dispatcher.Invoke(() => GuitarCheck(myargs.State));
(http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx)
So you have an event called OnButtonPress whos event handler is obviously executing on a thread that is not hosting VisualTreeHelper. The big question for me is...why? With a name like OnButtonPress it makes me think it should already be on the UI thread. Afterall, it is a button press right? So why is it executing on another thread to begin with?
Using a marshaling operation like Invoke or BeginInvoke is fine as long as you are aware of why it is needed and what it accomplishes for you. But, you really need to take a step back and identify what all is going on that would cause you to need to use a marshaling operation in the first place. There may be a bigger issue here that you need to address.

Delegating code to run from main thread for handling gui from main thread

I have some code which is been running by a backgroundworker I'd like some specific code which shows some GUI to run in the main thread context (2 reasons 1. it should be blocking 2.I know it's problematic to handle gui controls from a background worker)
I raise an event pass the class and listen to the event in the mainForm from there I check if invoke required and reinvoke. then call the public method of the instance I want to run in the main thread. I have a few questions:
is there any problem to handle data member which are created in the backgoundworker context from the main thread - for both reading and chaning valuse
is there any design pattern for such issue? Idealy I'd like to run any delegate- any return value and a few genric parameters- as func built in delegate- that is problematic because It means if I want to support up to 3 parameters with or without return values I'll have to have 6 events and 6 listeners which actually do the same - does anyone have an idea of how to do this correct?
Thanks!
I just wrote this for a similar question.
I use threads for these kind of stuff.
somewhere in my code:
// Definition
private static Thread TH;
....
// When process starts
TH = new Thread(new ThreadStart(Splash_MyCallBack));
TH.Start();
....
// This method starts the form that shows progress and other data
static private void Splash_MyCallBack()
{
frmLoading FL;
FL = new frmLoading();
FL.ShowDialog();
} /* Splash_MyCallBack*/
// Your process calls Splash_Stop when it is done.
static public void Splash_Stop()
{
TH.Abort();
} /* Splash_Stop*/
frmLoading performs the visual stuff, while in the background I have a very processor-intensive task.
My process reports to an interface its progress. frmLoading implements that interface so it is aware of it and can show whaever it is needed (2 progress bars in my case)
Tha only catch is, frmLoading must have this in the constructor:
Control.CheckForIllegalCrossThreadCalls= false;
which may be risky in some scenarios (not my case).
I think that the fact that the main process calls an interface to update progress, and the real interface consumes that is a pattern.
Hope this helps, I can add more stuff if you like.
Regards,
To answer your first question:
There shouldn't be any problems handling data created in the background worker. I've done it in a couple of applications and not had any issues.

Categories