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.
Related
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.
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.
Sorry for long title, I don't know even the way on how to express the question
I'm using a library which run a callback from a different context from the main thread (is a C Library), I created the callback in C# and when gets called I would like to just raise an event.
However because I don't know what will be inside the event, I would like to find a way to invoke the method without the problem of locks and so on (otherwise the third party user will have to handle this inside the event, very ugly)
Are there any way to do this?
I can be totally on the wrong way but I'm thinking about winforms way to handle different threads (the .Invoke thing)
Otherwise I can send a message to the message loop of the window, but I don't know a lot about message passing and if I can send "custom" messages like this
Example:
private uint lgLcdOnConfigureCB(int connection, System.IntPtr pContext)
{
OnConfigure(EventArgs.Empty);
return 0U;
}
this callback is called from another program which I don't have control over, I would like to run OnConfigure method in the main thread (the one that handles my winform), how to do it?
Or in other words, I would like to run OnConfigure without the need of thinking about locks
Edit 1:
I have a problem with this exception:
CallbackOnCollectedDelegate retrived
Message: Callback run on delegate 'G19dotNet!G19dotNet.LgLcd+lgLcdOnSoftButtonsCB::Invoke' collected in GarbageCollector. During unmanaged code delegates should be ensured will never be deleted until you are sure they will never be called
Edit 2:
Issue resolved by myself, thanks to Stackoverflow which always helps me!
For future reference: Defining a delegate as a function pointer
If you're using WinForms and you want to execute something on the UI thread, you need to call either Invoke or BeginInvoke on some control (be it a Button or a Form or whatever) that was created on that thread. You'll need a reference to it in order to do this.
For example, with your code and assuming that you have a reference to a form called form:
private uint lgLcdOnConfigureCB(int connection, System.IntPtr pContext)
{
form.Invoke(new MethodInvoker(() => OnConfigure(EventArgs.Empty)));
return 0U;
}
Before you call the 3rd party function, get a reference to Dispatcher.CurrentDispatcher. In the callback function, use dispatcher.Invoke.
What you end up with will look something like this:
class MyClass
{
private Dispatcher dispatcher;
public void runThirdParty()
{
this.dispatcher = Dispatcher.CurrentDispatcher;
callThirdPartyFunction(myCallBack);
}
public void myCallBack()
{
this.dispatcher.Invoke(new Action(() =>
{
//code to run here.
}));
}
}
There is a pattern for this called Event-based Asynchronous Pattern. The article linked is a great overview on how to use it. The AsyncOperation class is the key to this pattern.
This pattern might not fit perfectly with your problem that you are trying to solve, but it might give you some insights into the problem.
Thanks to Adam Robinson answer, I added a nice little utility function on my form:
private void runOnUIThread(Action function)
{
this.Invoke(new MethodInvoker(function));
}
And I'm using it like this:
runOnUIThread(() =>
{
example_lbl_status.Text = "Active";
});
I'm trying to work with Threadding and it seems to me like it's suspiciously difficult (I'm probably doing it wrong).
I want to load a file inside a BackgroundWorker and while that happens, "send" each new line to a separate Thread (not bgWorker). I'm using BlockingCollection and Add() each line, then I want to Take() them and process them in another thread.
Now, everything is straightforward with the BgWorker; but why is it impossible(isn't it?) to just declare a new thread in Form1.cs and have it perform like the BgWorker? In other words, why must you create a separate WorkerClass ( http://msdn.microsoft.com/en-us/library/7a2f3ay4(VS.80).aspx )?
I'm asking this because, you can access your BlockingCollection fine from within the BackgroundWorker, but you can't do it from a separate WorkerClass (since it's a plain vanilla separate class). (So what's the point of the BlockingCollection then if you can't use it for what it's meant?)
Also, BgWorkers have a ReportProgress(...) event/method. As far as I know, if you use that msdn example, you don't have squat in your Thread.
What am I missing here? Please help.
PS: Before you jump and tell me that It's not in any way more efficient to send lines to another thread, know that I'm doing this as a learning exercise. Trying to figure out how Threads work in C# and how you sync/communicate between/with them (and/or bgWorkers).
Answering specifically why working with threads is more difficult than working with a background worker....
The backgroundworker is actually a method for creating another thread wrapped up in an easier to use package. The reason working with threads directly is harder is because it's closer to the real thing.
For a similar comparison, using System.Net.Mail to send an email is just a simplified way of creating socket connections, etc... Under the hood, the System.Net.Mail classes do the detailed work. Similarly, under the hood, the BackgroundWorker does the detailed work of dealing with the threads.
As a matter of fact, the MSDN documentaiton for the backgroundWorker object starts out like this:
BackgroundWorker Class Updated:
September 2010
Executes an operation on a separate
thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
So if the backgroundworker class is supposed to make threading easier, why would people want to work with threads directly? Because of the issue you're having. Sometimes the "friendly wrapper" leads to a loss of fine control.
Edit - added
What you're asking about in the comments is thread synchronization. This article covers it pretty well.
http://msdn.microsoft.com/en-us/magazine/cc164037.aspx
and this article answers "communicating between threads" explicitly.
http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic63233.aspx
To answer your question in the title, yes "normal" threads can act like BackgroundWorker threads. You just have to create more of the wiring code yourself.
I wrote a simple application for scanning my music collection using a manually created thread. The main body of the thread is a method that loops over all of the folders under a specified root and fires an event each time it encounters a folder that contains some mp3 files.
I subscribe to this event in the main form of my application and update a DataGridView with the new information.
So the thread is kicked off by the following code:
this.libraryThread = new Thread(new ThreadStart(this.library.Build)) { IsBackground = true };
// Disable all the buttons except for Stop which is enabled
this.EnableButtons(false);
// Find all the albums
this.libraryThread.Start();
The method supplied to ThreadStart does some housekeeping and then calls the method that does the work:
private void FindAlbums(string root)
{
// Find all the albums
string[] folders = Directory.GetDirectories(root);
foreach (string folder in folders)
{
if (this.Stop)
{
break;
}
string[] files = Directory.GetFiles(folder, "*.mp3");
if (files.Length > 0)
{
// Add to library - use first file as being representative of the whole album
var info = new AlbumInfo(files[0]);
this.musicLibrary.Add(info);
if (this.Library_AlbumAdded != null)
{
this.Library_AlbumAdded(this, new AlbumInfoEventArgs(info));
}
}
this.FindAlbums(folder);
}
}
When this method finishes a final LibraryFinished event is fired.
I subscribe to these events in the main form:
this.library.Library_AlbumAdded += this.Library_AlbumAdded;
this.library.Library_Finished += this.Library_Finished;
and in these methods add the new album to the grid:
private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e)
{
this.dataGridView.InvokeIfRequired(() => this.AddToGrid(e.AlbumInfo));
}
and finish off (which reenables buttons etc.):
private void Library_Finished(object sender, EventArgs e)
{
this.dataGridView.InvokeIfRequired(() => this.FinalUpdate());
}
As you can see this is a lot of work which would be a whole lot simpler if I used a BackgroundWorker.
We have a DLL that monitors changes in status and looks for events from a separate, purchased product. Actually, it is a ScreenPop API from Siemens, for those of you who may know what that is. I am using C#.NET 3.5 as the platform.
This API takes a looong time to initialize, so we want to use a separate thread to initialize it. Currently, we have the functionality in a class called ScreenPop. The class monitors 2 events, a status change event and a screen pop event (data that tells us who the customer is that is calling).
The way this is currently implemented doesn't work, or at least doesn't work reliably. Within the ScreenPop class, there is an initialization method where all the long-running startup code is placed. This is called from the constructor of the class, like this:
public ScreenPop( string Address, int Ext, CallbackStatusType pStatusFunc,
CallbackScreenPopType pPopFunc
)
{
CallbackStatus = pStatusFunc;
CallbackPopup = pPopupFunc;
Thread t = new Thread( StartInBackground );
t.Start();
}
In the GUI code, the func at pStatusFunc updates a status label, and the func at pPopupFunc will fire off some other code to do the screen pop - right now it just displays the data from the event.
There is a lot of glue missing, but I hope you get the point. The problem with this approach is the GUI is not updated. I know the events fire and the event handlers run, and the callback functions are getting called and they seem like they should be running, but the GUI is never updated.
So, my question is, should I abandon this in favor of a BackgroundWorker approach? Or am I just missing something in getting the GUI to update?
More info on request...
Thanks,
Dave
You can never update the GUI from a different thread - only from the UI thread, which is the one that started the application. You need to use the Control.Invoke method to run code on the UI thread. Form instance, frmMain.Invoke.
You cannot use WinForms in a multithreaded apartment, to get around this, you have to marshal over to the UI thread to perform actions on it or get results. Since you are using C#3.5, you can make use of lambdas, generics, and extension methods to make a really clean and easy to use solution.
public static class ControlExtensions
{
public static TResult InvokeEx<TControl, TResult>(this TControl control,
Func<TControl, TResult> func)
where TControl : Control
{
if (control.InvokeRequired)
{
return (TResult)control.Invoke(func, control);
}
else
{
return func(control);
}
}
}
Now you can safely and easily make changes or get values.
this.InvokeEx(f => f.label1.Text = "Hello from another thread");
new Thread(() =>
{
string formTitle = this.InvokeEx(f => f.Text); // Safely get form title
}).Start();