I have a Windows Form Application (Form1) that allow the user to open another Forms (FormGraph). In order to open the FormGraph App I use a thread that open it.
Here is the code that the thread is running:
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
myGraph.Show();
}
My problem is that myGraph closed right after it's open.
1) Does anyone know why this is happening and how to make myGraph stay open?
2) After the user closed myGraph, How do I terminate the thread?
Many thanks!
The problem is not in the posted snippet. You'll need to start a new message loop with Application.Run() or Form.ShowDialog(). You'll also need to take care of thread properties so it is suitable to act as a UI thread. For example:
Thread t = new Thread(() => {
Application.Run(new Form2());
// OR:
//new Form2().ShowDialog();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
There are some awkward choices here. The form cannot be owned by any form on your main thread, that usually causes Z-order problems. You'll also need to do something meaningful when the UI thread's main form is closed. Sloppily solved here by using IsBackground.
Windows was designed to support multiple windows running on one thread. Only use code like this if you really have to. You should never have to...
The main problem you ahve is that you do not establish a message pump in the new thread.
Check
Run multiple UI Threads
for a good overview how to run a high perforamnce user interface using multiple threads (one per form / group of forms).
What you basically miss is the call to Application.Run to set up the message pump on the separate UI thread.
I think once the last form of a message pump closes - it will dispose itself and end.
Note that all this ASSUMES you WANT to open the window in a separate UI thread... otherwise you need to invoke back to the main UI thread for the creation and all manipulation of the window, so it gets attached to the existing message pump. There are GOOD cases for both - one keeps thigns simple, the other allows a LOT more performance as every window has a separate message pump and can thus act individually - this is for example used a lot in trading applications which may need to update graphs on a number of screens and havea bottleneck if running single threaded in the UI.
As a rule of thumb you should avoid manipulating the UI from threads (creating a form is a sort of manipulation to the UI). You should always manipulate the UI from the main thread.
The form is closing because the thread has finished and is therefore free'd along with its resouces (the form). To make the thread stay running you need a loop
e.g.
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
myGraph.Show();
while (myGraph.IsOpen)
{
//process incoming messages <- this could be fun on a thread....
}
}
You'll need a method of setting IsOpen (like a timeout or a button) and obviously you'll need to actually create IsOpen as a property of the form and set it to true when the form is created.
I'll add here the same as other users... You should have a good reason for not using the main thread.
If it takes a while to prepare the data for the form, you can do that in a separate thread to keep the application responsive. When the data is ready you can return the object to the main thread an let it show it.
You should declare a variable for the object in the form rather than locally in the method, so that it survives when you exit the thread.
When you are ready to show the form, you can use the Invoke method to make a method call that will be executed in the main thread.
do not create and show forms in non-main thread. do it in main form thread.
Or do this:
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
Application.Run(myGraph);
}
but first version is better
Why are you creating a form on a new thread? There are times you need to use a new thread but other times you can use form.ShowDialog() on the main thread.
What about if you show the form as if it was a Dialog? You can use
private void ThreadCreateCurvedGraph()
{
FormGraph myGraph = new FormGraph();
myGraph.CreateCurvedGraph(...);
myGraph.ShowDialog();
}
This way the call will block until the myGraph form is closed. As you have the myGraph created on a separated thread calling the blocking ShowDialog should block only that thread.
Perhaps this is garbage collection:
After ThreadCreateCurvedGraph() exits, myGraph goes out of scope and closes.
You need to organise a way of the thread to hold on to the instance and wait (using a blocking wait) for it to close.
Edit: For instance add:
Application.Run(myGraph)
to the end of the method.
(See comments from TomTom)
Related
I have to show a progress window in a different thread.
This is what I've done:
Thread loadT = new Thread(new ThreadStart(() =>
{
Loading ldd = new Loading();
ldd.SetContentMessage("Loading...");
ldd.Closed += (s, ec) =>
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
ldd.ShowDialog();
}));
loadT.SetApartmentState(ApartmentState.STA);
loadT.Start();
//do something
loadT.Abort();
But I don't think this is the right way. I want to use this window for different processes and i also want to set the window on the top of the others. Which is the best approach?
Ty!
You should do this the other way around when you are waiting for data and stuff to load.
Loading ldd = new Loading();
ldd.SetContentMessage("Loading...");
ldd.ShowDialog();
Thread loadT = new Thread(new ThreadStart() =>
{
//Do stuff here
});
loadT.Start();
Then you can get setup some events and such to either post updates to the loading window, or just leave it as is. You can also either monitor the threads state within the Loading window and close itself when the thread is complete or close the window from the thread.
as an example you could modify Loading to take a Thread as its parameter.
Thread loadT = new Thread(new ThreadStart() =>
{
//Do stuff here
});
Loading ldd = new Loading(loadT);
ldd.ShowDialog();
You can then move the starting of the thread, and monitoring of the thread/closing the window into the Loading class and it can look after itself.
There are 900,000 ways you can do this. You can also use BackgroundWorkers instead of spawning a new Thread, or you can use async/await in .Net 4.5+. Threading like this has been exhaustively done in the past and there should be lots of resources on google to help you in whatever path you decide to take. The important takeaway from this is your window should really be on the UI thread, and your loading should be done on another thread, not the other way around.
You could refer to the following blog post for an example of how to launch a WPF window in a separate thread the right way: http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/.
But you won't be able to mix controls that are created on different threads. A control can only be accessed on the thread on which it was originally created so it makes no sense to create a control on one thread and then trying to use it on another because this simply won't work because of the thread affinity.
Displaying a stand-alone top-level read-only window during the time a long-running operation is in progress is fine but you should probably close this window as soon as the operation has completed. You won't be able to move controls from this window to another one that was created on another thread anyway.
Can anybody please explain this statement written on this link
Invoke(Delegate):
Executes the specified delegate on the thread that owns the control's underlying window handle.
Can anybody explain what this means (especially the bold one) I am not able to get it clearly
The answer to this question lies in how C# Controls work
Controls in Windows Forms are bound to a specific thread and are not
thread safe. Therefore, if you are calling a control's method from a
different thread, you must use one of the control's invoke methods to
marshal the call to the proper thread. This property can be used to
determine if you must call an invoke method, which can be useful if
you do not know what thread owns a control.
From Control.InvokeRequired
Effectively, what Invoke does is ensure that the code you are calling occurs on the thread that the control "lives on" effectively preventing cross threaded exceptions.
From a historical perspective, in .Net 1.1, this was actually allowed. What it meant is that you could try and execute code on the "GUI" thread from any background thread and this would mostly work. Sometimes it would just cause your app to exit because you were effectively interrupting the GUI thread while it was doing something else. This is the Cross Threaded Exception - imagine trying to update a TextBox while the GUI is painting something else.
Which action takes priority?
Is it even possible for both to happen at once?
What happens to all of the other commands the GUI needs to run?
Effectively, you are interrupting a queue, which can have lots of unforeseen consequences. Invoke is effectively the "polite" way of getting what you want to do into that queue, and this rule was enforced from .Net 2.0 onward via a thrown InvalidOperationException.
To understand what is actually going on behind the scenes, and what is meant by "GUI Thread", it's useful to understand what a Message Pump or Message Loop is.
This is actually already answered in the question "What is a Message Pump" and is recommended reading for understanding the actual mechanism that you are tying into when interacting with controls.
Other reading you may find useful includes:
What's up with Begin Invoke
One of the cardinal rules of Windows GUI programming is that only the
thread that created a control can access and/or modify its contents
(except for a few documented exceptions). Try doing it from any other
thread and you'll get unpredictable behavior ranging from deadlock, to
exceptions to a half updated UI. The right way then to update a
control from another thread is to post an appropriate message to the
application message queue. When the message pump gets around to
executing that message, the control will get updated, on the same
thread that created it (remember, the message pump runs on the main
thread).
and, for a more code heavy overview with a representative sample:
Invalid Cross-thread Operations
// the canonical form (C# consumer)
public delegate void ControlStringConsumer(Control control, string text); // defines a delegate type
public void SetText(Control control, string text) {
if (control.InvokeRequired) {
control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text}); // invoking itself
} else {
control.Text=text; // the "functional part", executing only on the main thread
}
}
Once you have an appreciation for InvokeRequired, you may wish to consider using an extension method for wrapping these calls up. This is ably covered in the Stack Overflow question Cleaning Up Code Littered with Invoke Required.
There is also a further write up of what happened historically that may be of interest.
A control or window object in Windows Forms is just a wrapper around a Win32 window identified by a handle (sometimes called HWND). Most things you do with the control will eventually result in a Win32 API call that uses this handle. The handle is owned by the thread that created it (typically the main thread), and shouldn't be manipulated by another thread. If for some reason you need to do something with the control from another thread, you can use Invoke to ask the main thread to do it on your behalf.
For instance, if you want to change the text of a label from a worker thread, you can do something like this:
theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));
If you want to modify a control it must be done in the thread in which the control was created. This Invoke method allows you to execute methods in the associated thread (the thread that owns the control's underlying window handle).
In below sample thread1 throws an exception because SetText1 is trying to modify textBox1.Text from another thread. But in thread2, Action in SetText2 is executed in the thread in which the TextBox was created
private void btn_Click(object sender, EvenetArgs e)
{
var thread1 = new Thread(SetText1);
var thread2 = new Thread(SetText2);
thread1.Start();
thread2.Start();
}
private void SetText1()
{
textBox1.Text = "Test";
}
private void SetText2()
{
textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });
In practical terms it means that the delegate is guaranteed to be invoked on the main thread. This is important because in the case of windows controls if you don't update their properties on the main thread then you either don't see the change, or the control raises an exception.
The pattern is:
void OnEvent(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(() => this.OnEvent(sender, e);
return;
}
// do stuff (now you know you are on the main thread)
}
this.Invoke(delegate) make sure that you are calling the delegate the argument to this.Invoke() on main thread/created thread.
I can say a Thumb rule don't access your form controls except from main thread.
May be the following lines make sense for using Invoke()
private void SetText(string text)
{
// 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)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
There are situations though you create a Threadpool thread(i.e worker thread) it will run on main thread. It won't create a new thread coz main thread is available for processing further instructions. So First investigate whether the current running thread is main thread using this.InvokeRequired if returns true the current code is running on worker thread so call
this.Invoke(d, new object[] { text });
else directly update the UI control(Here you are guaranteed that you are running the code on main thread.)
It means that the delegate will run on the UI thread, even if you call that method from a background worker or thread-pool thread. UI elements have thread affinity - they only like talking directly to one thread: the UI thread. The UI thread is defined as the thread that created the control instance, and is therefore associated with the window handle. But all of that is an implementation detail.
The key point is: you would call this method from a worker thread so that you can access the UI (to change the value in a label, etc) - since you are not allowed to do that from any other thread than the UI thread.
Delegate are essentially inline Action's or Func<T>. You can declare a delegate outside the scope of a method which you are running or using a lambda expression(=>); because you run the delegate within a method, you run it on the thread which is being run for the current window/application which is the bit in bold.
Lambda example
int AddFiveToNumber(int number)
{
var d = (int i => i + 5);
d.Invoke(number);
}
It means that the delegate you pass is executed on the thread that created the Control object (which is the UI thread).
You need to call this method when your application is multi-threaded and you want do some UI operation from a thread other than the UI thread, because if you just try to call a method on a Control from a different thread you'll get a System.InvalidOperationException.
I have a main form class in C# and a side-class. I am creating instances of side-class and calling a method of that class from that instance. That method starts new thread. Now I am creating multiple instances and calling methods for each of them. So, multiple threads are started. Now I have implemented a method in side-class to ensure the thread is closed when going out from the method associated with the thread.
I don't know if a user suddenly clicks the X(close) button of the main frame window, then how to handle the threads which are inside that side-class.
P.S - The side-class's instances are instantiated within a method of the main form class. So, at the time of disposing, I don't have the instances with me, so that I can stop them.
If by closing the Main window you are terminating the application, then you can just set IsBackground to true in you worker threads, in the side-classes, when you create them. As so:
var newThread = new Thread(DoWork) {IsBackground = true};
newThread.Start();
However, if closing your 'Main' window is not the end of the application, then the Main window should keep an array of references to the instantiated side-classes. It should then dispose/ set a flag on each side instance to signal that the thread should stop (how you do this is up to you - a flag periodically checked in the side-class might be appropriate). This call should happen in the OnClose of the 'Main' window.
You could set the side-threads to BackGroundWorkers which close when the application ends.
Or in the form.Closing event call their respective join() methods.
This will let the application wait untill the threads are finished.
I'm new to WPF (and computer science in general) and I was given a small project from my boss where there are 5 tabs, each that go to a different site. After logging in, the user is directed to the website of the 1st tab. In the background, the 4 other tabs should be loading in the background.
Each has the following name: "tabItem1", "tabItem2", "tabItem3", "tabItem4" up to "tabItem5"
Inside each there is a up to "webBrowser5".
I think that I have to use threading to load the pages in the background, but I'm not sure how to implement it. I tried creating 4 different threads in the MainWindow such as:
public MainWindow()
{
InitializeComponent();
Thread thread1 = new Thread(Update1);
thread1.SetApartmentState(ApartmentState.STA);
thread1.Start();
Thread thread2 = new Thread(Update2);
thread2.SetApartmentState(ApartmentState.STA);
thread2.Start();
Thread thread3 = new Thread(Update3);
thread3.SetApartmentState(ApartmentState.STA);
thread3.Start();
Thread thread4 = new Thread(Update4);
thread4.SetApartmentState(ApartmentState.STA);
thread4.Start();
}
private void Update1()
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
tabItem2.Focus();
}
);
}
private void Update2()
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
tabItem3.Focus();
}
);
}
//...Goes up to Update4
This seems to only focus on the last thread and also it doesn't do it the background. I appreciate any guidance and help. Thanks!
That IS what the dispatcher is doing, operating on the main thread. You told the main thread to set focus because the object is on the main thread.
The problem:
The answer lies in why you must do this. You cannot operate on a windows control in any other thread than the thread it was created on. You also can't create a control in one thread, and set it as a child of a control in another thread.
What this means to you... is that what your boss asked you to do can't be done. The only thing you can do in the background is calculate algorithms. At best, you'll be able to load data, and operate on data, and interpret data, but if you want to have that data be displayed in, or converted into, windows controls, you must do that on the main thread.
The only solution:
However, you can have multiple UIThreads. Which means you can create multiple Windows. So, the must-do alternative is to create windows on separate threads for each tab content, then host the thread-windows on each tab.
Threading windows
Host process window
Cross thread hosting
I do not agree with Xaade, I think you can do what you need using only this code:
Dispatcher.BeginInvoke((Action)(() =>
{
// load the pages
}), DispatcherPriority.Background, null);
That code will be executed in background, so, there you can load every webBrowser you need.
You just need to specify the DispatcherPriority to Background.
I have a windows forms application that runs two threads simultaneously, with the UI thread running in the task bar. The UI thread actually performs completely separate functionality from the other process, but in the case that a new user logs into the application, I need to pop up a setup window from the non-UI thread.
Here is the code from my Program.cs:
static void Main()
{
ThreadStart start = new ThreadStart(Waiting.wait);
Thread waiting = new Thread(start);
waiting.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
Application.Run(TaskBarIcon.getInstance());
}
Currently, before TaskBarIcon can fully instantiate, one configuration method must be finished running in the waiting thread. This is achieved by passing a lock back and forth.
I would like to have this set up menu pop up while the configuration method is processing, and have the method wait to complete until the setup menu is done running. However, unless I run the set up menu directly from the Application.Run() method, I cannot even get the menu to show up properly.
I'm very new to C#....would be able to do this quickly in Java, but C# seems to do things differently.
Any suggestions or solutions would be greatly appreciated!
badPanda
I suspect what it is happening is that the setup menu form is not receiving windows messages on the worker thread and that is why it is not showing up. All forms and controls need a message pump to work properly. There are various different ways of getting a message pump started, but the two most applicable to you are:
Application.Run
Form.ShowDialog
If you call ShowDialog on the setup menu form then it should show up on the worker thread. Of course the call blocks until the form is closed so that will prevent the remainder of the configuration method from executing, but then again that may be exactly what you want.
If you want the main UI thread (the one calling Application.Run) to wait until this configuration method is finished then use a WaitHandle to signal when the configuration task is complete. It might look like the following.
static void Main()
{
var configured = new ManualResetEvent(false);
var worker = new Thread(
() =>
{
// Do some stuff here.
CallYourConfigurationMethod();
configured.Set() // Signal that configuration is complete.
// Do some more stuff here.
});
worker.Start();
configured.WaitOne();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
Application.Run(TaskBarIcon.getInstance());
}