corlettk
corlettk

Reputation: 13574

How to show form in front in C#

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.

Upvotes: 26

Views: 95799

Answers (11)

phuong
phuong

Reputation: 1

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;
}

Upvotes: 0

Willie Bronkhorst
Willie Bronkhorst

Reputation: 11

This did the job perfectly :

formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();

Upvotes: 1

bluish
bluish

Reputation: 27380

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);
    }
}

Upvotes: 5

Esen
Esen

Reputation: 973

Form.Activate() worked in my case.

Upvotes: 6

user2162266
user2162266

Reputation: 39

Activate() worked for me too.

BringToFront() did nothing in this case, I don't know why.

Upvotes: 3

cablehead
cablehead

Reputation:

Simply

yourForm.TopMost = true;

Upvotes: 58

Wael Azmy
Wael Azmy

Reputation: 11

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!

Upvotes: -1

alex
alex

Reputation: 11

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;

    }
}

}

Upvotes: 1

corlettk
corlettk

Reputation: 13574

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.

Upvotes: 0

P Daddy
P Daddy

Reputation: 29537

  1. You said that it works fine when you use Application.Run. Why don't you want to use Application.Run, then?
  2. Have you tried calling BringToFront() from OnLoad or OnShown?

Upvotes: 3

ChrisV
ChrisV

Reputation: 3423

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).

Upvotes: 5

Related Questions