Folks,
Please does anyone know how to show a Form from an otherwise invisible application, and have it get the focus (i.e. appear on top of other windows)? I'm working in C# .NET 3.5.
I suspect I've taken "completely the wrong approach"... I do not Application.Run(new TheForm ()) instead I (new TheForm()).ShowModal()... The Form is basically a modal dialogue, with a few check-boxes; a text-box, and OK and Cancel Buttons. The user ticks a checkbox and types in a description (or whatever) then presses OK, the form disappears and the process reads the user-input from the Form, Disposes it, and continues processing.
This works, except when the form is show it doesn't get the focus, instead it appears behind the "host" application, until you click on it in the taskbar (or whatever). This is a most annoying behaviour, which I predict will cause many "support calls", and the existing VB6 version doesn't have this problem, so I'm going backwards in usability... and users won't accept that (and nor should they).
So... I'm starting to think I need to rethink the whole shebang... I should show the form up front, as a "normal application" and attach the remainer of the processing to the OK-button-click event. It should work, But that will take time which I don't have (I'm already over time/budget)... so first I really need to try to make the current approach work... even by quick-and-dirty methods.
So please does anyone know how to "force" a .NET 3.5 Form (by fair means or fowl) to get the focus? I'm thinking "magic" windows API calls (I know
Twilight Zone: This only appears to be an issue at work, we're I'm using Visual Studio 2008 on Windows XP SP3... I've just failed to reproduce the problem with an SSCCE (see below) at home on Visual C# 2008 on Vista Ulimate... This works fine. Huh? WTF?
Also, I'd swear that at work yesterday showed the form when I ran the EXE, but not when F5'ed (or Ctrl-F5'ed) straight from the IDE (which I just put up with)... At home the form shows fine either way. Totaly confusterpating!
It may or may not be relevant, but Visual Studio crashed-and-burned this morning when the project was running in debug mode and editing the code "on the fly"... it got stuck what I presumed was an endless loop of error messages. The error message was something about "can't debug this project because it is not the current project, or something... So I just killed it off with process explorer. It started up again fine, and even offered to recover the "lost" file, an offer which I accepted.
using System;
using System.Windows.Forms;
namespace ShowFormOnTop {
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
Form1 frm = new Form1();
frm.ShowDialog();
}
}
}
Background: I'm porting an existing VB6 implementation to .NET... It's a "plugin" for a "client" GIS application called MapInfo. The existing client "worked invisibly" and my instructions are "to keep the new version as close as possible to the old version", which works well enough (after years of patching); it's just written in an unsupported language, so we need to port it.
About me: I'm pretty much a noob to C# and .NET generally, though I've got a bottoms wiping certificate, I have been a professional programmer for 10 years; So I sort of "know some stuff".
Any insights would be most welcome... and Thank you all for taking the time to read this far. Consiseness isn't (apparently) my forte.
Cheers. Keith.
Simply
yourForm.TopMost = true;
There's an overload of Form.ShowDialog() which takes an IWin32Window object. That IWin32Window is treated as the parent window for the form.
If you have the parent window as a System.Windows.Forms.Form, go ahead and just pass it. If not, get the HWND (maybe by P/Invoking to FindWindow()), and create a dummy IWin32Window implementation that just returns the HWND (More details).
Form.Activate()
worked in my case.
- You said that it works fine when you use
Application.Run
. Why don't you want to useApplication.Run
, then? - Have you tried calling
BringToFront()
fromOnLoad
orOnShown
?
This is the final solution I wrote after 20 different attempts:
/* A workaround for showing a form on the foreground and with focus,
* even if it is run by a process other than the main one
*/
public static void ShowInForeground(this Form form, bool showDialog = false)
{
if (showDialog)
{
//it's an hack, thanks to http://stackoverflow.com/a/1463479/505893
form.WindowState = FormWindowState.Minimized;
form.Shown += delegate(Object sender, EventArgs e) {
((Form)sender).WindowState = FormWindowState.Normal;
};
form.ShowDialog();
}
else
{
//it's an hack, thanks to http://stackoverflow.com/a/11941579/505893
form.WindowState = FormWindowState.Minimized;
form.Show();
form.WindowState = FormWindowState.Normal;
//set focus on the first control
form.SelectNextControl(form.ActiveControl, true, true, true, true);
}
}
I've hacked this from an application I've been working on. We have a large application that loads a series of modules written by different teams. We have written one of these modules, and needed to have a login dialog open during this initialization. It was set to '.TopMost=true', but that didn't work.
It uses the WindowsFormsSynchronizationContext to open a dialog box, and then get the result of the dialog box back.
I rarely do GUI coding, and suspect this may be overkill, but it might help someone if they get stuck. I had problems with understanding how state is passed to the SendOrPostCallback, as all the examples I could find didn't use it.
Also this is taken from a working application, but I've removed several bits of code, and changed some of the details. Apologies if it doesn't compile.
public bool Dummy()
{
// create the login dialog
DummyDialogForm myDialog = new DummyDialogForm();
// How we show it depends on where we are. We might be in the main thread, or in a background thread
// (There may be better ways of doing this??)
if (SynchronizationContext.Current == null)
{
// We are in the main thread. Just display the dialog
DialogResult result = myDialog.ShowDialog();
return result == DialogResult.OK;
}
else
{
// Get the window handle of the main window of the calling process
IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;
if (windowHandle == IntPtr.Zero)
{
// No window displayed yet
DialogResult result = myDialog.ShowDialog();
return result == DialogResult.OK;
}
else
{
// Parent window exists on separate thread
// We want the dialog box to appear in front of the main window in the calling program
// We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread
object resultState = null;
WindowsFormsSynchronizationContext.Current.Send(
new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState);
if (resultState is DialogResult)
{
DialogResult result = (DialogResult) resultState;
return result == DialogResult.OK;
}
else
return false;
}
}
}
Activate()
worked for me too.
BringToFront()
did nothing in this case, I don't know why.
It would appear that is behaviour is specific to XP... Hence I can't reproduce it on Vista.
http://www.gamedev.net/community/forums/topic.asp?topic_id=218484
EDIT: PS: It's past my bedtime (2 AM;-).
Thanx all for your responses... there's a "few things" I can try... I might even go into the office tomorrow to try them... Yeah, yeah... I had a life once, but I traded it for a haircut and a job ;-)
Cheers all. Keith.
This did the job perfectly :
formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
I got a code in the project.
private static extern bool SetForegroundWindow(
IntPtr hWnd);
public static void ShowToFront(Form form)
{
FormWindowState oldState = form.WindowState;
form.WindowState = FormWindowState.Minimized;
form.Show();
form.Activate();
form.TopLevel = false;
form.TopLevel = true;
form.SelectNextControl(form.ActiveControl, true, true, true, true);
SetForegroundWindow(form.Handle);
form.Focus();
form.WindowState = oldState;
}
This is what I use to bring an open form that is part of my application to the front. You can even use it with a button. But the form needs to be open or the application will break.
"YourOpenForm" has to be the name of your form from the properties window.
private void button1_Click(object sender, EventArgs e)
{
Application.OpenForms["YourOpenForm"].BringToFront();
}
Good Luck!
来源:https://stackoverflow.com/questions/987053/how-to-show-form-in-front-in-c-sharp