Show a Form without stealing focus?

Viewed 79505

I'm using a Form to show notifications (it appears at the bottom right of the screen), but when I show this form it steals the focus from the main Form. Is there a way to show this "notification" form without stealing focus?

19 Answers

Hmmm, isn't simply overriding Form.ShowWithoutActivation enough?

protected override bool ShowWithoutActivation
{
  get { return true; }
}

And if you don't want the user to click this notification window either, you can override CreateParams:

protected override CreateParams CreateParams
{
  get
  {
    CreateParams baseParams = base.CreateParams;

    const int WS_EX_NOACTIVATE = 0x08000000;
    const int WS_EX_TOOLWINDOW = 0x00000080;
    baseParams.ExStyle |= ( int )( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW );

    return baseParams;
  }
}

Stolen from PInvoke.net's ShowWindow method:

private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;

[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
     int hWnd,             // Window handle
     int hWndInsertAfter,  // Placement-order handle
     int X,                // Horizontal position
     int Y,                // Vertical position
     int cx,               // Width
     int cy,               // Height
     uint uFlags);         // Window positioning flags

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

static void ShowInactiveTopmost(Form frm)
{
     ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
     SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
     frm.Left, frm.Top, frm.Width, frm.Height,
     SWP_NOACTIVATE);
}

(Alex Lyman answered this, I'm just expanding it by directly pasting the code. Someone with edit rights can copy it over there and delete this for all I care ;) )

If you're willing to use Win32 P/Invoke, then you can use the ShowWindow method (the first code sample does exactly what you want).

Doing this seems like a hack, but it seems to work:

this.TopMost = true;  // as a result the form gets thrown to the front
this.TopMost = false; // but we don't actually want our form to always be on top

Edit: Note, this merely raises an already created form without stealing focus.

The sample code from pinvoke.net in Alex Lyman/TheSoftwareJedi's answers will make the window a "topmost" window, meaning that you can't put it behind normal windows after it's popped up. Given Matias's description of what he wants to use this for, that could be what he wants. But if you want the user to be able to put your window behind other windows after you've popped it up, just use HWND_TOP (0) instead of HWND_TOPMOST (-1) in the sample.

You might want to consider what kind of notification you would like to display.

If it's absolutely critical to let the user know about some event, using Messagebox.Show would be the recommended way, due to its nature to block any other events to the main window, until the user confirms it. Be aware of pop-up blindness, though.

If it's less than critical, you might want to use an alternative way to display notifications, such as a toolbar on the bottom of the window. You wrote, that you display notifications on the bottom-right of the screen - the standard way to do this would be using a balloon tip with the combination of a system tray icon.

Create and start the notification Form in a separate thread and reset the focus back to your main form after the Form opens. Have the notification Form provide an OnFormOpened event that is fired from the Form.Shown event. Something like this:

private void StartNotfication()
{
  Thread th = new Thread(new ThreadStart(delegate
  {
    NotificationForm frm = new NotificationForm();
    frm.OnFormOpen += NotificationOpened;
    frm.ShowDialog();
  }));
  th.Name = "NotificationForm";
  th.Start();
} 

private void NotificationOpened()
{
   this.Focus(); // Put focus back on the original calling Form
}

You can also keep a handle to your NotifcationForm object around so that it can be programmatically closed by the main Form (frm.Close()).

Some details are missing, but hopefully this will get you going in the right direction.

This works well.

See: OpenIcon - MSDN and SetForegroundWindow - MSDN

using System.Runtime.InteropServices;

[DllImport("user32.dll")]
static extern bool OpenIcon(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

public static void ActivateInstance()
{
    IntPtr hWnd = IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;

    // Restore the program.
    bool result = OpenIcon(hWnd); 
    // Activate the application.
    result = SetForegroundWindow(hWnd);

    // End the current instance of the application.
    //System.Environment.Exit(0);    
}

You don't need to make it anywhere near as complicated.

a = new Assign_Stock(); 
a.MdiParent = this.ParentForm;
a.Visible = false;   //hide for a bit.                 
a.Show(); //show the form. Invisible form now at the top.
this.Focus(); //focus on this form. make old form come to the top.
a.Visible = true; //make other form visible now. Behind the main form.

enter image description here

Github Sample

Form.ShowWithoutActivation Property

Add this in your child form class

    protected override bool ShowWithoutActivation
        {
            get { return true; }
        }

Working Code

Form2

   public partial class Form2 : Form
    {
        Form3 c;
        public Form2()
        {
            InitializeComponent();
             c = new Form3();
        }

        private void textchanged(object sender, EventArgs e)
        {


            c.ResetText(textBox1.Text.ToString());
            c.Location = new Point(this.Location.X+150, this.Location.Y);
            c .Show();

//removethis
//if mdiparent 2 add this.focus() after show form

            c.MdiParent = this.MdiParent;
            c.ResetText(textBox1.Text.ToString());
            c.Location = new Point(this.Location.X+150, this.Location.Y);
            c .Show();
           this.Focus();
////-----------------


        }


       
    }

Form3

   public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();
            //ShowWithoutActivation = false;
        }
        protected override bool ShowWithoutActivation
        {
            get { return true; }
        }


        internal void ResetText(string toString)
        {
            label2.Text = toString;
        }

     
    }

When you create a new form using

Form f = new Form();
f.ShowDialog();

it steals focus because your code can't continue executing on the main form until this form is closed.

The exception is by using threading to create a new form then Form.Show(). Make sure the thread is globally visible though, because if you declare it within a function, as soon as your function exits, your thread will end and the form will disappear.

Related