Update WinForm Controls from another thread _and_ class - c#

I am making a WinForms program, which requires separate threads
For readability and maintainability, i have separated all non-GUI code out into different classes. This class also 'generates' another class, which does some processing. However, i have now run into the issue where i need to change a WinForms control (append a string to textbox) from a thread that was initiated in a different class
I have searched around, and found solutions for different threads, and in different classes, but not both and the solutions provided seem incompatible (to me)
This may be the biggest 'lead' however: How to update UI from another thread running in another class
Class Hierarchy example:
class WinForm : Form
{
...
Server serv = new Server();
}
// Server is in a different thread to winform
class Server
{
...
ClientConnection = new ClientConnection();
}
// Another new thread is created to run this class
class ClientConnection
{
//Want to modify winform from here
}
I understand that eventhandlers are probably the way to go, but i can't work out how to do so in this situation (I am also open to other suggestions ;) )
Any help appreciated

It does not matter from which class you are updating the form. WinForm controls have to be updated on the same thread that they were created on.
Hence, Control.Invoke, allows you to execute a method on the control on its own thread. This is also called asynchronous execution, since the call is actually queued up and executed separately.
Look at this article from msdn, the example is similar to your example. A separate class on a separate thread updates a list box on the Form.
----- Update
Here you do not have to pass this as a parameter.
In your Winform class, have a public delegate that can update the controls.
class WinForm : Form
{
public delegate void updateTextBoxDelegate(String textBoxString); // delegate type
public updateTextBoxDelegate updateTextBox; // delegate object
void updateTextBox1(string str ) { textBox1.Text = str1; } // this method is invoked
public WinForm()
{
...
updateTextBox = new updateTextBoxDelegate( updateTextBox1 ); // initialize delegate object
...
Server serv = new Server();
}
From the ClientConnection Object, you do have to get a reference to the WinForm:Form object.
class ClientConnection
{
...
void display( string strItem ) // can be called in a different thread from clientConnection object
{
Form1.Invoke( Form1.updateTextBox, strItem ); // updates textbox1 on winForm
}
}
In the above case, 'this' is not passed.

you can use backgroundworker to make your other thread,
it allow you to deal easily with your GUI
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

Related

Dealing with user interface inside a thread (Compact-Framework)

We want to display a "Loading, please wait..." screen before the application starts executing other functions on a Win CE 5.0 powered device. The application is being developed using .NET Compact Framework 3.5 (C#).
The issue is that, the UI is only updated once the set of current processes are completed, to a stage where other functions will only run with user interaction. C# has a Form.Shown() event, which would allow the application to run other functions, only ONCE the form has been displayed. However, the Compact-Framework does NOT include.
The solution I've approached was using multi-threading, where I would have one thread which would display the "Loading, please wait..." screen, and the other would take care of other function.
The issue with Threading is, when managing UI components, it gives an error if not applied the correct techniques:
public Form1()
{
InitializeComponent();
ThreadStart tstart = new ThreadStart(showLoad);
Thread t1 = new Thread(tstart);
Thread t2 = new Thread(checkConnect);
t1.Start();
t2.Start();
}
private void checkConnect()
{
conn.portConnect(); //Connects to port Successfully
if (conn.isConnected == true) //Variable which checks the connectivity status
{
panelMENUshow();
}
else
{
panelCONFIGshow();
}
}
private void showLoad()
{
if (imgLoading.InvokeRequired)
{
imgLoading.Invoke((Action)(() => imgLoading.Show())); //Image box displaying "Loading, please wait..." shows successfully if I use Control.Invoke
}
//If I don't use Control.Invoke I get the following error:
//"Control.Invoke must be used to interact with controls created on a separate thread."
}
On the showLoad() function, it is not a problem to add Control.Invoke. However, the functions panelMENUshow() and panelCONFIGshow() contains many bits of code that manages UI components, and it would be not practical to use Control.Invoke in every line of code referring to a UI component.
Is there a way of:
stopping the threading but carry on running the code that involves UI management?
practically manage UI components within a thread?
PS: The approach was based on the answer of this post.
Use the refresh function to force the control to be immediately redrawn.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.refresh(v=vs.90).aspx
When writing WinForm apps you want to keep the complexities of threading away from the main UI thread. I've seen too many applications with thread code weaving in and out of them, tying the logic into a knot.
Instead, model anything that requires any kind of threading as a component that, while it may use threads internally, presents a friendly, even-based model to the outside world. These components should not have any direct interaction with your UI.
Given that, your code would look something more like this (just an example, not syntax checked and probably with lots of typos etc, but it will give you an idea):
public class CommunicationObject
{
// you will probably have several EventArgs to define to pass extra info
public event EventHandler<EventArgs> Connected;
// you need this instance to dispatch events to the UI thread
private Control _invoker;
public CommunicationObject(Control invoker)
{
_invoker = invoker;
// start a thread here, or better yet, add an Enabled property or
// Start method to kick it off
}
// from the thread that is doing the real work, call this when you are connected
private void OnConnected()
{
_invoker.Invoke(() =>
{
EventHandler<EventArgs> handler = Connected;
if (handler != null)
{
handler(this, EventArgs.Empty); // eventually you might need your own event args
}
});
}
}
public class Form1 : Form
{
private CommunicationObject _comm;
public Form1()
{
InitializeComponent();
imgLoading.Show(); // show msg until connected
_comm = new CommunicationObject(this);
_comm.Connected += Comm_Connected; // wire up event handler
}
private void Comm_Connected(object src, EventArgs e)
{
if (imgLoading.Visible)
{
imgLoading.Hide(); // hide once connected
}
panelMENUshow();
}
}
Note that the form has no threads in it at all. Push that complexity into stand-alone objects. It might seem like a bit more work, but you will thank yourself later!

Code starts only when Application.Run() is invoked WPF application

I have a method which is invoked in class A and it is defined in class B:
class B{
[STAThread]
public static void ScanForAxisCameras() {
DNSSDService service = new DNSSDService();
DNSSDEventManager eventManager = new DNSSDEventManager();
eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(eventManager_ServiceFound);
DNSSDService browse = service.Browse(0, 0, "_axis-video._tcp", null, eventManager);
Application.Run();//if not invoked everything above does not start
}
}
class A{ ...before invoking..... B.ScanForAxisCameras(); ....after invoking....}
The code in class B "starts"/works only if I invoke Application.Run(). But it causes that all the code in class A ....after invoking.... method does not work. How to handle it so it will not freeze the application?
Edit: the class A is class MainWindow.xaml.cs. It is WPF application.
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
createGUI();
}
private void createGUI() {
LocalNetworkScanner.ScanForAxisCameras();//when there is no Application.Run() ScanForAxisCameras() does not work.
}
}
The WPF UI thread on which you call ScanForAxisCameras() already has a message loop. I believe the problem with your code is that all objects you create inside ScanForAxisCameras have the local scope:
public static void ScanForAxisCameras() {
DNSSDService service = new DNSSDService();
DNSSDEventManager eventManager = new DNSSDEventManager();
eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(eventManager_ServiceFound);
DNSSDService browse = service.Browse(0, 0, "_axis-video._tcp", null, eventManager);
Application.Run();//if not invoked everything above does not start
}
Without Application.Run(), your objects (service, eventManager, browse) may be getting destroyed and finalized as soon as ScanForAxisCameras finishes. So, the events you're looking for (like ServiceFound) may not even have a chance to get fired.
If you call Application.Run(), then ScanForAxisCameras doesn't exit (at least not until Application.Run() itself exits). That keeps your objects alive and functional.
Try refactoring your code to keep the references to these objects in member fields of your class (or in static variables, FWIW). I believe that should fix the problem.
[EDITED] On a side note, the [STAThread] attribute doesn't make sense in that context (unless you use ScanForAxisCameras as an entry point for a new thread - apparently, that's not the case here).
You can introduce a new Run()-method in your App in the App.xaml.cs file.
Here you can perform custom actions before the application itself gets initialized.
Further information here.
public partial class App : Application
{
public new void Run()
{
// Do your stuff here
B.DoStuff();
// Call the base method
base.Run();
}
}
Application.Run starts the message loop for that particular thread, if there is no message loop then there is no notification for your objects to know they have to do something.
The code in class B "starts"/works only if I invoke Application.Run(). But it causes that all the code in class A ....after invoking.... method does not work.
Run is a blocking call therefore any code after that call is not reachable until the application is closing down i.e. when you exit the message loop.
How to handle it so it will not freeze the application?
In short, you can't. Run will always block so any code you need to run as part of your application startup will have to happen before the call.
After your edit to mention that this is a WPF application then Application.Run as a static method is not the right way to go here. If you need to run initialization when your application starts then you can do what has already been suggested and override the Run method of the Application class, or alternatively (maybe more appropriately) you can hook into the OnStartup event e.g.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// code before startup
base.OnStartup(e);
// code after startup
}
}
It seems as though in this situation you would need to add Application.Run() in a different class. Run() accepts nothing, ApplicationContext, Form. This controls the lifetime of the application and should be called before class A, unless class A is the entry point.
See http://msdn.microsoft.com/en-us/library/ms157900.aspx for details.
A Windows Forms application starts when the Main method is called. You can implement initialization procedures on the Main function. However, to initialize a Windows Forms application fully and start it routing Windows Forms events, you need to invoke Application.Run.
you can read about Application here

Accessing WinForms Controls from a serial port in a class

First, the apology: I'm new to posting questions on this site, so I apologize for formatting or information errors.I have seen many answers to taking data from a serial port dropped on a form and using it to populate text boxes, graphs, etc. on the main form, using "Invoke" because the serial port is running in a different thread.
I am trying to "generalize" some comm stuff we use all the time in to a class (yes, the old VB6 programmer is trying to grow up :-) and I'm having issues. I can do some things if I force a form name in the main program.cs and use the same namespace for the class, but this sorta defeats the purpose. I've also tried adding an event on the "received" even of the serial port in the class to raise an event on the main form. The event tries to get raised but a cross thread exception occurs.
The code at this point is quite large, so I'll try to "outline" it. In simplistic form, assuming I have a for called "Form1" which contains a text box called textbox1 and a class called "SerialThing":
Form1:
SerialThing mySerialThing ;
Form1_Load:
mySerialThing = new SerialThing();
DisplayData()
Textbox1.Text = "You Got Data!";
SerialThing:
Static SerialPort myDevice;
Init()
myDevice = new SerialPort;
myDevice.DataReceived += new SerialDataReceivedEventHandler(devicePort_DataReceived);
devicePort_DataReceived()
this.Invoke(new EventHandler(DisplayData));
The above will work if the serial port is placed on the main form, but not if created inside the class.
Again, sorry if too complex, or too simplistic. I am looking for an "easy" way to do this, but keep the class "generalized" (ideally not have to have the workspace names match, etc).
-Vin
There are many, many ways to do this. I'll present the classic approach using a custom event, delegates, and Invoke(), as I think it's important to understand that process. Once you've got this down, you can jump to some of the newer approaches.
First, in your SerialThing() class, you declare a Custom event to pass out data when it is received:
class SerialThing
{
public delegate void DataReceivedDelegate(string data);
public event DataReceivedDelegate DataReceived;
static SerialPort myDevice;
public SerialThing()
{
myDevice = new SerialPort();
myDevice.DataReceived += new SerialDataReceivedEventHandler(myDevice_DataReceived);
}
void myDevice_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// ... grab the data and place into a string called "data" ...
string data = "";
// raise our custom event:
if (DataReceived != null)
{
DataReceived(data);
}
}
}
Now, over in Form1, you subscribe to that custom event when you create the instance of SerialThing. Additionally, when that event is received, you marshal the call from the secondary thread to the main thread using InvokeRequired, Invoke, and a delegate:
public partial class Form1 : Form
{
SerialThing mySerialThing;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += new SerialThing.DataReceivedDelegate(mySerialThing_DataReceived);
}
private delegate void DataReceivedDelegate(string data);
void mySerialThing_DataReceived(string data)
{
if (this.InvokeRequired)
{
this.Invoke(new DataReceivedDelegate(mySerialThing_DataReceived), new Object[] { data });
}
else
{
textBox1.Text = data;
}
}
}
EDIT: In response to your comments below...
Think of a delegate as simply a "pointer to a method". When you execute the delegate, the associated method gets run.
The InvokeRequired() portion determines if the code is running in a different thread than the one that created the control. In this case, the control is the Form itself (this). If true is returned, then the event was received in a different thread. We then proceed to this.Invoke() line inside the true portion of the If block. Again this refers to the Form. Thus the Form is requesting to Invoke ("run") the passed delegate on the thread that created it (the main UI thread). We create a instance of the delegate that actually points to the same method we are already in resulting in a recursive call. The second parameter is simply an array of Object used to pass the parameters along with the delegate.
When Invoke() is run we end up re-entering the method because of the recursive call. At this point, however, the InvokeRequired() check will return false as we are now running in the main UI thread. Therefore we drop down into the false portion of the If statement where we update the TextBox. In this pattern it is safe to update an GUI controls in the else block of the If statement.
Note that a recursive call isn't necessary here. This is simply a style choice. We could have instead used a second "helper" function that the delegate pointed to, and Invoked that instead. The recursive approach reduces the number of methods required.
This is perhaps the most verbose approach to solving this type of problem. I like it, though, as it shows the flow of events and data, and movement between the threads.
We could shorten all the Form code to just this, using anonymous delegates:
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += delegate (string data)
{
this.Invoke((MethodInvoker)(delegate() { textBox1.Text = data; }));
};
}
I don't know about you, but as a former VB6 programmer myself, that just looks weird when you first see that type of thing.
I've also used components that I know have things running in different
threads, yet the "form code" has never had to use the delegate stuff,
so maybe there's something that can be buried into the class?
Yes, it's possible to bake some "magic" into a class so that it raises events already on the main UI thread, thus not requiring any Invoke() calls. One way to do this is thru using a SynchronizationContext.
Another possibility for approaching this type of problem would be to use a BackgroundWorker() control which has events such as ProgressChanged() and RunWorkerCompleted() that are raised in the main UI thread for you (they do the necessary invoking type stuff under the hood for you).

C# Windows Forms Application - Updating GUI from another thread AND class?

I've searched a ton, but I can't seem find anything relating to my specific problem.
I want to be able to update my MainUI form from another class (SocketListener) and within that I have a thread that handles the networking (clientThread). Right now I can run simple outputs from the networking thread such as writing to the debugger output and creating a MessageBox.
But what I really want to do is be able to invoke code from the clientThread that will do things on my MainUI instance. How can I do this?
Also, if anyone wants specific portions of the code then I can post it to help give you a better understanding of what I'm asking.
Best regards!
Check the InvokeRequired of the Control class, and if it's true, then call the Invoke and pass in a delegate (usually an anonymous method) that does what you want to do on the client's thread.
Example:
public void DoWork(Form form)
{
if (form.InvokeRequired)
{
// We're on a thread other than the GUI thread
form.Invoke(new MethodInvoker(() => DoWork(form)));
return;
}
// Do what you need to do to the form here
form.Text = "Foo";
}
Yes, you could add a constructor to your class that takes the MainUI form as a parameter. That is the quick way to do it, but it introduces a "backward" dependency from your class to the MainUI where, in theory, no dependency is required.
As an alternative, I would suggest adding a public event to your class that the MainUI form could then subscribe to. When your class needs to update the MainUI (or controls within the MainUI), the class would simply "raise" the event. This will call the MainUI's method that it registered at the time of subscription. Since it is a method of the MainUI form already, all you have to do is update the appropriate controls on the form, making sure to take the InvokeRequired property of each control into account.
And when doing that, here's the construct I've been using in all my code.
class NetworkEventArgs : EventArgs { /* defined class here */ }
private void NetworkEventHandler(object sender, NetworkEventArgs e)
{
Invoke( ( MethodInvoker ) delegate {
myTextBox.Text = e.Message;
}
}
I've based this on the blog entry here. I have not had this approach fail me, so I see no reason to complicate my code with a recursive check of the InvokeRequired property.
you can define an event your clientThread class
and handle it in mainform
when clientThread needs aware mainform to do something(like update some control status)
you should Fire the event
so mainform gets paramter from event and invokes update function

How do I pass arguments to a Thread in .Net

I have function along these lines:
public void view(string msg)
{
messagebox.show(msg);
}
.
.
I want to pass arguments to this it from a thread.. I'm using .Net 1.1. How can I do this?
For .NET 1.1 there is no direct way but to use an object having both the method and the state, in this example (modified from the MSDN sample), the ThreadState class is instanced and passed the desired state, then its method is called and made to use the passed state.
public class ThreadState {
private string msg;
// The constructor obtains the state information.
public ThreadState(string msg) {
this.msg = msg;
}
public void view() {
//Do something with msg
}
}
public class Example {
public static void Main() {
ThreadState ts = new ThreadState("Hello World!");
// Create a thread to execute the task, and then
// start the thread.
Thread t = new Thread(new ThreadStart(ts.view));
t.Start();
t.Join();
}
}
For .NET > 1.1 (original question didn't state version.)
You pass the argument in the Start method. You will receive an object which you need to cast back to the proper type.
Thread t = new Thread(view);
t.Start("Hello");
public void view(object msg)
{
string m = (string)msg;
//Use msg
}
Either that, or use a ParameterizedThreadStart delegate.
The ParamaterizedThreadStart delegate is not present in .NET 1.1 (2003) nor does thread.Start take an Object param in 1.1. However you could try something like:
dict[mythread.name] = myval; //dict is a class scoped variable.
mythread.Start();
There are various ways to do that. One is to use the ParameterizedThreadStart delegate, which allows passing a single parameter of type Object to the thread. Change your view method to accept Object, then cast Object to String inside the method.
Create a class, set your properties as arguments and run related function of the class.
Dim run = New Runner()
run.mile = 20
run.pace = "slow"
Thr.Start(run.Process())
Or you need to use a global scope variable. Unfortunately no other way for .NET 1.1
The first code snippet provided by Vinko is exactly what you need under .NET 1.x as the original Threading namespace offered no in-built mechanism for parameterizing _beginthread.
Thus, you create a state class which contains the data you need, as well as the method which will be used for the delegate in the "new Thread()" statement, as Vinko has shown.
I was about to tap out a sample, and then I saw his sample code. If it's "not working" it's worth being explicit as to why, because by the naked eye that code looks all too familiar.
One "spin" on this is to properly encapsulate the thread construction as well as the thread start/join behavior.
Another option is to use ThreadPool.QueueUserWorkItem(), which isn't quite the same and can result in poor ThreadPool performance if over-used.
Another option is to create a thread that is blocked on a signal, e.g. ManualResetEvent, which is set when a data member has been initialized. The target data member can be as simple as an object reference as shown above, or you could use an ArrayList, Queue or Stack object (with proper locking) to implement a sort of "queue processor" where work items can be enqueued and processed by a dedicated thread, and where the dedicated thread remains dormant (blocked waiting for a signal) until there is work available.

Categories

Resources