How to make a form stay above another - c#

In my .NET application I am showing a form with a "Please wait" message if some task takes a while to tell the user that the program still works. This form has to run in it's own thread since the main thread is the one doing work and therefore busy. I read that one can use Form.Owner for this task, but I don't think that works if the forms run on different threads.
The problem is that the wait form can be hidden behind the main form in which case the user couldn't see it and can't bring it to the front, since it has no task bar button (an it musn't have one).
My question is if it is possible to let the wait form stay above the main form without making it an AlwaysOnTop form (which would stay above ALL windows)?

Your main thread should not be doing work. It should be handling UI and nothing else.
The right way to do this is to perform any and all time-consuming work in an asynchronous manner (e.g. in a separate thread), and keeping all of your user interface in the main thread. Then you can simply show the "Please wait" message form by calling the Form.ShowDialog() method. This will force focus to that dialog and keep it on top of its parent form (don't forget to pass the parent form reference to the ShowDialog() method).
Without a code example, I can't say exactly how this would look in your specific scenario. But the general idea looks something like this:
private void button1_Click(object sender, EventArgs e)
{
using (Form form = MyWaitMessageForm())
{
form.Shown += async (sender1, e1) =>
{
await Task.Run(() => MyLongRunningWork());
form.Close();
}
form.ShowDialog(this);
}
}

You can use the Form.TopMost property for this.
You can also use the following code:
protected void SetZOrder(IntPtr bottom, IntPtr top) {
const int flags = 0x0002 | 0x0001;
NativeMethods.SetWindowPos(bottom, top, 0, 0, 0, 0, flags);
}
bottom - the pointer of the main form, top - the pointer of the wait form. To get a pointer, use Form.Handle property. And call the SetZOrder via the BeginInvoke method of the parent form.

You could use the Form.ShowDialog(IWin32Window)
Form1 testDialog = new Form1();
testDialog.ShowDialog(this)

Related

Can I show a MessageBox but still use the form?

It is possible that when I use:
MessageBox.Show("hello");
..to still use the form but the MessageBox is open like a second window?
because currently, when I show the MessageBox, I need to first click yes or no then I can use my form again.
Yes, you can!
If you simply want to display a MessageBox, don't care what happens with it, and don't want to wait until it's closed, you may launch it on a separate thread. The easiest way to do that would be using Task.Run().
Here's an example:
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => MessageBox.Show("hello"));
// The remaining code will run without waiting for the MessageBox to be closed.
}
A couple of notes worth mentioning:
Only use this for simple message boxes where you don't care about the result. If you want to act based on the result and execute something (on the main thread), things get a little bit trickier.
You won't be able to keep the MessageBox on top of the form. Once you interact with the form, it will come on top. If you need to keep the MessageBox on top and still have the ability to interact with the form, a custom MessageBox (i.e., form) would be better in that case because you can set the Owner property to keep it on top.
No. The application focus remains on the Message Box until it is dismissed. According to the documentation:
It is a modal window, blocking other actions in the application until the user closes it.
What you can do is create your own form, style it to look like a standard Message Box, and show that form using the .Show() functionality on an instance of it:
var messageBox = new MyCustomMessageBox("hello");
messageBox.Show();
If you want the functionality to be identical in usage, you could even add a static method to your custom form which encapsulates it:
public static void Show(string message)
{
new MyCustomMessageBox(message).Show();
}
Though what I wouldn't recommend doing is calling your custom form MessageBox, that would just be asking for confusion.

Modeless Form calling Modal Form is blocking initial Form

I start with a form A.
The form A call a form B with .Show().
So form A and form B are both accessible.
Now, I wan't form B calling form C with ShowDialog(), because I don't want form B be accessible while form C is open.
The problem is : form A is inaccessible.
In this scenario, how can I have both form A and form C accessible, but not form B?
This is entirely by design, a dialog disables all windows in an application. There's a good reason for that, outlined in this answer.
In brief, the Drastic Failure scenario is that a user could use a command in form A that creates another instance of form B, one that isn't disabled. Which allows you to display C again, now you have two dialogs showing.
You may well sputter that this can never happen in your case. That's okay but you'll then have to undo what ShowDialog() does. Which requires gymnastics, you have to pinvoke EnableWindow() to re-enable the form A instance. But you have to do so after the ShowDialog() call but before it ends. Something you can do by using Control.BeginInvoke() on the UI thread. The trickorama looks like this:
private void ShowDialogButton_Click(object sender, EventArgs e) {
using (var dlg = new Form3()) {
// Find the main form instance
var main = Application.OpenForms.OfType<Form1>().Single();
this.BeginInvoke(new Action(() => {
EnableWindow(main.Handle, true);
}));
if (dlg.ShowDialog(this) == DialogResult.OK) {
// etc..
}
}
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr handle, bool enable);
You can also put the EnableWindow() call in the dialog's Shown event handler, that avoids having to use the BeginInvoke trick. But this way is more universal, dialogs should in general not be in the business of knowing what other windows run in an app. The use of Form1 in this code is ugly enough as-is.
Modal windows are such that they require users input and dismissal before allowing her to return to other part of applications. As such, you can't use them if you want to enable user to interact with more than one window.
You will have to manually handle this situation by disabling window B (setting Enabled to false) before showing window C, and enabling it back again once window C is dismissed.

How to show a WinForms Modal Dialog from a WPF App Thread

I have a WPF application. The main window of this application has a button. I am opening a WinForms modal dialog in a separate thread when this button is clicked. The trouble I am having is that the dialog does not behave like a modal i.e it is still possible to switch focus to the main window, whereas, I require to allow focus on the newly opened dialog and it should not be possible to select the main window.
Note: I cannot move the modalDialog.ShowDialog(); outside of the delegate because the dialog form creates controls dynamically and this means that these controls must remain on the thread that it was created. To be more clear, if I move the modalDialog.ShowDialog(); outside I will get an exception like so:
Cross-thread operation not vaild: Control 'DynamicList' accessed from a thread other than the one it was created on.
Any ideas as to how I might make the form behave as a modal?
Here is the code:
private void button1_Click(object sender, RoutedEventArgs e)
{
DoSomeAsyncWork();
}
private void DoSomeAsyncWork()
{
var modalDialog = new TestForm();
var backgroundThread = new Thread((
delegate()
{
// Call intensive method that creates dynamic controls
modalDialog.DoSomeLongWaitingCall();
modalDialog.ShowDialog();
}
));
backgroundThread.Start();
}
You should always create controls on the UI thread. If you do that, calling ShowDialog() through Dispatcher should work.

Dialog stops the execution of the code,is any way to stop it in c#?

I am displaying dialog on the main form, now one for loop is working behind but when that dialog will displayed code execution will be stopped, but I don't want to let stop the execution of the code, is any other any way to do that ?
EDIT: I am using now thread to do that and my code is like
Thread t;
private void StartParsingByLoop()
{
t = new Thread(new ThreadStart(RunProgress));
t.Start();
for (int i = 0; i < dialog.FileNames.Length; i++)
{
cNoteToParsed.AllContrctNotesFilePath.Add(dialog.FileNames[i].ToString());
}
cNoteToParsed.ParseContractNote();
if (cNoteToParsed.NOfContrctNoteParsed > 0)
LoadTransactionsInDataGridView();
t.Abort();
}
private void RunProgress()
{
frmProgress progressForImportingTran = new frmProgress("Importing Transactions", "ok");
progressForImportingTran.ShowDialog();
}
Now I have problem is that the dialog that shows the progress does not behave like dialog and gives access of the main form and if we try to access the main form then dialog goes to hide. And I dont want to make the dialog be hide.
You can let a different thread handle the loop.
Response to edit: Can you provide more details, perhaps some code? what is the loop doing? what form do you display?
(this answer is based on the assumption that we are taking about a winforms app)
Show the form using the Show method, rather than ShowDialog. By passing a reference to the main form, the dialog will stay on top of the main form even if it is not modal:
TheDialog dialog = new TheDialog();
dialog.Show(this);
Note though that the user can still interact with the controls on the main form, so you might want to disable some controls, depending on your scenario.
You state in your question that there are requirements that prevent you from using threading for this. This kind of requirement strikes me as odd, and it is a pity because this is one of the typical scenarios when you would want to use some sort of asynchronous construct. By performing heavy work on the UI thread, you get some drawbacks, including:
The UI will not be responsive - if you want to allow the user to cancel the work by clicking a button, that will be tricky to achieve in a robust manner.
The UI will not redraw properly since the UI thread is busy performing other work.
Do not use ShowDialog() but Show() to display the dialog windows. Show() will immediately return to the caller whereas ShowDialog() will hold the execution. Note that when using Show() your dialogs won't be modal anymore.
OK, so you don't need modal dialog, you need a mechanism for your user not to be able to select your main form while processing is enabled.
Modal dialog doesn't mean that execution is stopped - it just happens somewhere else.
There are several methods to do this, and you ruled out new thread creation (don't know why, it would solve it elegantly). If don't use thread, you'll have another problem - your processing should be done in CHUNKS and every little while you'll have to do something like Application.DoEvents() to enable your application to process messages and not be frozen to the user.
So, if you can create a method in the main form that shows your 'please wait' dialog which will perform some work and later do some more until is finished, you can do this:
create a new form (wait dialog)
start a timer inside of it and wire timer to the PARENT form
timer interval should be 1
ShowDialog() the form
on timer event do small amount of work (don't allow it to go more then 1/10 of seconds)
Can you do that?
Anyway:
task can't be split into small workable pieces
you can't use threads
you want your UI to be responsive
PICK 2. You can't have all 3 in Winforms.

Starting multiple gui (WinForms) threads so they can work separetly from one main gui in C#?

I've one MainForm window and from that user can press 3 buttons. Each of the button starts new Form in which user can do anything he likes (like time consuming database calls etc). So i decided to put each of the forms in it's own threads:
private Thread subThreadForRaportyKlienta;
private Thread subThreadForGeneratorPrzelewow;
private Thread subThreadForRaporty;
private void pokazOplatyGlobalne() {
ZarzadzajOplatamiGlobalneDzp varGui = new ZarzadzajOplatamiGlobalneDzp();
varGui.ShowDialog();
}
private void pokazRaportyKlienta() {
RaportyDzpKlient varGui = new RaportyDzpKlient();
varGui.ShowDialog();
}
private void pokazRaportyWewnetrzne() {
RaportyDzp varGui = new RaportyDzp();
varGui.ShowDialog();
}
private void pokazGeneratorPrzelewow() {
ZarzadzajPrzelewamiDzp varGui = new ZarzadzajPrzelewamiDzp();
varGui.ShowDialog();
}
private void toolStripMenuGeneratorPrzelewow_Click(object sender, EventArgs e) {
if (subThreadForGeneratorPrzelewow == null || subThreadForGeneratorPrzelewow.IsAlive == false) {
subThreadForGeneratorPrzelewow = new Thread(pokazGeneratorPrzelewow);
subThreadForGeneratorPrzelewow.Start();
} else {
}
}
private void toolStripMenuGeneratorRaportow_Click(object sender, EventArgs e) {
if (subThreadForRaporty == null || subThreadForRaporty.IsAlive == false) {
subThreadForRaporty = new Thread(pokazRaportyWewnetrzne);
subThreadForRaporty.Start();
} else {
}
}
private void toolStripMenuGeneratorRaportowDlaKlienta_Click(object sender, EventArgs e)
{
if (subThreadForRaportyKlienta == null || subThreadForRaportyKlienta.IsAlive == false) {
subThreadForRaportyKlienta = new Thread(pokazRaportyKlienta);
subThreadForRaportyKlienta.Start();
} else {
}
}
I've got couple of questions and i hope someone could explain them:
When i use Show() instead of ShowDialog() the windows just blink for a second and never shows. What's the actual difference between those two and why it happens?
When i use ShowDialog everything seems normal but i noticed not everything gets filled properly in one of the gui's (one listView stays blank even thou there are 3 simple add items in Form_Load(). I noticed this only in one GUI even thou on first sight everything works fine in two other gui's and i can execute multiple tasks inside those Forms updating those forms in background too (from inside the forms methods). Why would this one be diffrent?
What would be proper way of doing this? Tasks performed in each of those Forms can be time consuming and i would like to give user possibility to jump between those 4 windows without problem so he can execute what he likes.
The difference is with Modal and Modeless Windows Forms.
Modeless forms let you shift the
focus between the form and another
form without having to close the
initial form
Show() method is used for this purpose
Show() shows the new form, then returns. If this is all the thread is doing than the thread will exit, and that will destroy the form.
ShowDialog() shows the form, and then begins running a message pump, until the form is hidden or destroyed, ShowDialog() doesn't return, so your thread keeps running.
If You mean for these forms to each behave like a separate application window. then you could also use Application.Run() after form.Show() to run a message pump for the form on that thread. The drawback to doing it this way, is that when any one of your forms is closed, it might end up taking down the whole process because of the way WM_QUIT is handled.
But other than the way you would deal with closing down your application, Form.ShowDialog() is very much like Form.Show() followed by Application.Run(). The conditions that cause the message pump to exit are a bit different between these to, so you would choose one or the other mostly based on how you want to your application to handle closing one of your forms.
You should put the time-consuming tasks in their own BackgroundWorker threads. Keep all of the forms in the main thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
1: Show() is not blocking, that is it shows the window and then returns. Afterwards, the varGui variable goes out of scope and is finalized by the garbage collector => disappears.
2: You'd need to show the updating code to get a definite answer, but as you can only update the contents of a form when running in the thread that created the form. Doing it otherwise is unreliable, so is the usual culprit when form updates don't work. In a method of a form class, call:
if (InvokeRequired) {
.Invoke(..); // call back this same method on the right thread
} else {
// dowork
}
to manage the UI.
3: The proper way is what Jake wrote: use one thread for all GUI stuff and BackgroundWorker threads for, well, background work.

Categories