I am developing a plugin for an application, that application "consumes" my code (classLibrary), and executes the Init() method inside his own Thread.
Inside the Init() I have a while(true) statement, so that my plugin can run continuously.
Yesterday, I started to make a windowsForm for configuration of my plugin (using XML), and now I want to show it, but it keeps vanishing. My code is as follows:
Doing this will show the form, but, it wont re-paint because it is launched on that same thread as the while(true) is.
MaForm settingsForm = null;
void init(){
While(true){
if(settingsForm == null){
settingsForm = new MaForm();
settingsForm.show();
}
}
}
Version that shows, but then vanishes.
MaForm settingsForm = null;
Thread worker = null;
void init(){
While(true){
if(worker == null){
worker = new Thread(new ThreadStart(formStuff));
worker.Start();
}
}
}
void formStuff()
{
if(settingsForm == null){
settingsForm = new MaForm();
settingsForm.show();
}
}
What am I doing wrong? Is there something about Threading I am missing?
What do you guys think?
The thread is starting, showing your form, then finishing up and shutting down (which closes the form).
Showing a form on a separate thread is nearly always problematic. Forms require a message pump to be running - so they typically will only work properly if they're started and run on the GUI thread.
One option would be to invoke the function to show your form onto your main thread. This will make your form load (and run) on the main thread.
Alternatively, you can start an entire message pump on the form's thread, and set the thread to STA (this is important). However, I suggest avoiding this approach if possible.
you can try this: create the form, enter the infinite loop, call DoEvents() so that your form can process windows messages:
if(settingsForm == null){
settingsForm = new MaForm();
settingsForm.show();
}
while (settingsForm != null && settingsForm.Visible)
{
System.Windows.Forms.Application.DoEvents();
}
EDIT: may be you can replace the true condition by a check on the SettingsForm visibility. When the form is closed, it's a waste to stay in an infinite loop.
A good way of dealing with threading issues in C# is to comment out using System.Threading; at the top of your classes and forms. You may have some compelling reason for showing forms with a Thread, but probably not, since Form.Show() is not a blocking call.
if you're trying to show a form from your Main() method, try using ShowDialog() instead. This call will block until the form is closed.
Related
I have written a WordAddIn that allows the user to call on some metadata for the current document. Via a custom button in the ribbon, they can call a WPF. The WPF calling is realized as follows:
System.Windows.Application app = null;
and then in the method called by the button:
if (app == null)
{
app = new System.Windows.Application { ShutdownMode = ShutdownMode.OnExplicitShutdown };
app.Run();
}
MainWindow win = new MainWindow(graph);
app.Dispatcher.Invoke((Action)(() => { win.Show(); }));
The first time the button is clicked after Word started, nothing happens and it becomes impossible to edit content in the word document. The second time the button is clicked the WPF object loads and is shown, this works for any button click afterwards too. So it seems the first time the dispatcher is called, it hangs. How do I prevent this?
I'm not sure why you want to dispatch the call anyway since this is the same thread. You only need to marshall calls to UI thread when the "current" thread is not a UI thread, which is not your case - you only have one thread.
Secondly, Application.Run is a blocking method and should not be called in the Add-In context. You can't create a WPF application inside Add-In application. BTW, Application.Run always runs on the current thread, which in your case is the same one Word Add-In runs on. And this how it is supposed to be.
If I understand you correctly, you are creating a WPF application because you don't want to use WinForms technology but WPF. Do it without Application.Run and do not dispatch calls because there is no reason to do so.
I got help with this in the Microsoft WPF forums. Creating and calling app in a new thread does the trick, as app does indeed block the current thread it is called in.
if (app == null)
{
Thread thread = new Thread(new ThreadStart(() =>
{
app = new System.Windows.Application { ShutdownMode = ShutdownMode.OnExplicitShutdown };
autoResetEvent.Set();
app.Run();
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
else
{
autoResetEvent.Set();
}
autoResetEvent.WaitOne(); //wait until app has been initialized on the other thread
app.Dispatcher.Invoke((Action)(() => { new MainWindow(graph).Show(); }));
}
I'm trying to use a C# DLL that I have access to the code of, but I can't actually change the code and build a custom version of it. The calling code is a C# WinForms project and the C# DLL also uses WinForms to handle Windows system events. The problem is that the DLL uses Application.Run() inside of it using a background thread, and there's built-in way to kill or stop that thread. Here is a snippet of the code:
public class DllClass
{
private Thread uithread = null;
private bool uithreadstarted = false;
public DllClass()
{
uithread = new Thread(new ThreadStart(RunDll));
uithread.IsBackground = true;
uithread.SetApartmentState(ApartmentState.STA);
uithread.Start();
do
{
Thread.Sleep(100);
} while (uithreadstarted == false);
}
private void RunDll()
{
//other init stuff here
uithreadstarted = true;
Application.Run();
}
}
Apparently the way I'm expected to kill it is by using Application.Exit(), but that also exits my own WinForms project, which is not what I want to happen. If I just close my application without calling Application.Exit(), the DLL continues running in the background. I want to be able to instantiate the DllClass object, use it, and then shut it down when I'm done. I came up with a method to get the Thread object of the thread that it's running in, but calling Thread.Abort() on it does not actually kill the thread. Is there any way to forcibly abort the Application.Run() call from outside of the DLL?
If you can find a window handle that was created by the DLL background thread (such as a form or hidden application window), you can post a WM_QUIT message to that handle and that should cause the DLL to exit the message loop cleanly.
you will need to get an instance of the form that is running in the other thread then call form.BeginInvoke and from there call Application.Exit
How about Application.ExitThread
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# Splash Screen Problem
I am new to c# , i am working on splash screen which runs when the software starts.. I have a function in splash Screen class which checks the database. I am using thread to call the function
sc = new splashScreen();
checkDLLThread = new Thread(new ThreadStart(sc.checkDLLS).BeginInvoke);
checkDLLThread.Start();
while (checkDLLThread.IsAlive)
{
Thread.Sleep(200);
}
Problem is UI is blocked until the thread is Alive. And in final it give me database connection status message.
Here is my code. I have used checkDLLThread.join() but it also doesnt work.
A splashscreen is simply an image to 'amuse' the user while your app is loading. Use the app_load method to execute code on startup:
Like so: (in app.xaml and app.xaml.cs)
<Application /some references to stuff/ Startup="Application_Startup" >
private void Application_Startup(object sender, StartupEventArgs e)
{
// your startupcode
}
Also, I think the BackGroundworker class is better for things like this, if you don't want to bother the UI.
Unblocking the UI thread requires returning from your event handler. There is no alternative to doing that. Here is some pseudo-code:
OnStartup:
Start new Thread
Disable UI
Show Splash Sceen
Return!
Thread:
Check Database
if (not ok)
Show Message box
Exit Application
else
Enable UI
Remove Splash Screen
The trick is to let the thread show the message and so one once it is done. Don't wait for the thread, let the thread do it itself.
Your thread probably needs to use the Invoke function to access the UI. You might wan't to read about that a bit because there is no way around it if you want to do asynchronous work on a background thread.
The following code launches a "splash screen" on a separate thread whilst your application (in my example below it is called MainForm()) loads or initialises. Firstly in your "main()" method (in your program.cs file unless you have renamed it) you should show your splash screen. This will be a WinForm or WPF form that you wish to show the user at start up. This is launch from main() as follows:
[STAThread]
static void Main()
{
// Splash screen, which is terminated in MainForm.
SplashForm.ShowSplash();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Run UserCost.
Application.Run(new MainForm());
}
In your SplashScreen code you need something like the following:
public partial class SplashForm : Form
{
// Thredding.
private static Thread _splashThread;
private static SplashForm _splashForm;
public SplashForm()
{
InitializeComponent();
}
// Show the Splash Screen (Loading...)
public static void ShowSplash()
{
if (_splashThread == null)
{
// show the form in a new thread
_splashThread = new Thread(new ThreadStart(DoShowSplash));
_splashThread.IsBackground = true;
_splashThread.Start();
}
}
// Called by the thread
private static void DoShowSplash()
{
if (_splashForm == null)
_splashForm = new SplashForm();
// create a new message pump on this thread (started from ShowSplash)
Application.Run(_splashForm);
}
// Close the splash (Loading...) screen
public static void CloseSplash()
{
// Need to call on the thread that launched this splash
if (_splashForm.InvokeRequired)
_splashForm.Invoke(new MethodInvoker(CloseSplash));
else
Application.ExitThread();
}
}
This launches the splash form on a separate background thread allowing you to proceed with the rendering of your main application simultaneously. To display messages about loading you will have to pull information from the main UI thread, or work in purely aesthetic nature. To finish off and close the splash screen down when your application has been initialised you place the following inside the default constructor (you could overload the constructor if you wanted to):
public MainForm()
{
// ready to go, now initialise main and close the splashForm.
InitializeComponent();
SplashForm.CloseSplash();
}
The code above should be relatively easy to follow.
I hope this helps.
Your approach is good, but you should run both simultaneously. A good use of static fields can do the job easily. Instead of:
while (checkDLLThread.IsAlive)
{
Thread.Sleep(200);
}
You should:
Show the Splash Form
Set the form to be hidden on start, i.e. set Opacity to 0
Check steadily for a variable in the SplashForm when your form is completely initialized
Set Opacity back to 1 when the thread is complete. i.e. variable changes
i.e.:
public Form1(){
InitializeComponent();
Opacity = 0;
while(sc.IsComplete){}
Opacity = 1;
}
And inside your SplashForm, you should have something like:
internal static bool IsComplete;
internal static void CheckDLLS()
{
//after doing some stuff
IsComplete = true;
}
I am facing an issue with communication between threads in a C#.NET application.
Hope someone will guide me in the right direction about the possible solutions.
I have an application in C#.NET.It is a windows form application.
My application has two threads - One thread is the main thread (UI thread) and the other one is the child thread. Lets call the child thread the "workerThread"
There is only one form used in the application.Lets call this form the "MainForm"
The child thread is started when the MainForm loads (used the form's "Load" event handler to start the thread)
In the MainForm class, I have a variable named "stopWork" which is a public boolean variable and it serves as a flag to indicate whether the child thread should continue working or should it stop
I have another class (besides the MainForm class) which contains the method that I execute in the the child thread. Lets call this second class the "WorkerClass".
I pass a reference to the current form (the MainForm) into the constructor of the "WorkerClass"
I have a button "stop" in the main form which sets "stopWork" to "true" if its clicked and then calls "workerThread.Join()" to wait for the child thread to finish excecution.
In the child thread, the method "doWork" keeps checking the status of "parentForm.stopWork" inside a for loop. If "stopWork" is set to "true" then the loop breaks and subsequently the method ends.
Now, the issue is, once I am clicking the "stop" button ,the application hangs.
I am pasting parts of the code below so that it is easier to understand :
public partial class MainForm : Form
{
Thread workerThread = null;
ThreadStart workerThreadStart = null;
WorkerClass workerClass = null;
public bool stopWork = true;
/*.......... some code ............*/
private void MainForm_Load(object sender, EventArgs e)
{
workerThreadStart = new ThreadStart(startWork);
workerThread = new Thread(workerThreadStart);
stopWork = false;
workerThread.Start();
}
private void startWork()
{
workerClass = new WorkerClass(this);
}
private void buttonStop_Click(object sender, EventArgs e) //"stop" button
{
if (workerThread != null)
{
if (workerThread.IsAlive == true)
{
stopWork = true;
workerThread.Join();
}
}
}
/*.......... some more code ............*/
}
public class WorkerClass
{
MainForm parentForm=null;
/*......... some variables and code ........*/
public WorkerClass(MainForm parentForm)
{
this.parentForm=parentForm;
}
/* .............. some more code ...........*/
public void doWork()
{
/*.......... some variables and code ...........*/
for(int i=0;i<100000;i++)
{
// ** Here is the check to see if parentForm has set stopWork to true **
if(parentForm.stopWork==true)
break;
/*......... do some work in the loop ..........*/
}
}
/********* and more code .........*/
}
I think I may know where the problem lies.
The problem is in the "doWork" method in the child thread trying to access "stopWork" variable in the parent form when already the parent form is blocked by calling the "workerThread.Join()" method. So ,I think this is a "deadlock" problem.
Am I right in identifying the problem ? Or am I wrong and the problem lies somewhere else ?
In case this is indeed a deadlock, what are the possible solutions to solve this ?
I did a bit of googling and found lots of resources on thread synchronisation and how to avoid deadlocks. But I could not understand how to apply them specifically to my problem.
I would really appreciate any help or guidance on resolving this issue.
Yes, the code you wrote is highly vulnerable to deadlock. The BackgroundWorker class is especially prone to cause this kind of deadlock.
The problem is located in code we can't see in your snippet, the WorkerClass. You are surely doing something there that affects the UI in one way or another, always the primary reason to consider creating a thread in the first place. You probably use Control.Invoke() to have some code run on the UI thread and update a control. Perhaps also to signal that the worker thread is completed and, say, set the Enable property of a button back to true.
That's deadlock city, such code cannot run until the UI thread goes idle, back to pumping its message loop. It will never be idle in your case, it is stuck in Thread.Join(). The worker thread can't complete because the UI thread won't go idle, the UI thread can't go idle because the worker thread isn't finishing. Deadlock.
BackgroundWorker has this problem too, the RunWorkerCompleted event cannot run unless the UI thread is idle. What you need to do is not block the UI thread. Easier said than done, BGW can help you get this right because it runs an event when it completes. You can have this event do whatever you now do in the code past the Thread.Join() call. You'll need a boolean flag in your class to indicate that you are in the 'waiting for completion' state. This answer has relevant code.
Use a BackgroundWorker for this task instead. When you want to stop the task's execution, call the background worker's CancelAsync method.
Generally speaking, rolling your own threading code (on any platform) is a recipe for disaster if you don't have an expert-level understanding of multithreading (and even then it's still dangerous).
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)