Show a Form without stealing focus?

2020-01-22 14:02发布

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?

标签: c# .net winforms
17条回答
ゆ 、 Hurt°
2楼-- · 2020-01-22 14:32

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;
  }
}
查看更多
劫难
3楼-- · 2020-01-22 14:33

I know it may sound stupid, but this worked:

this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
查看更多
Deceive 欺骗
4楼-- · 2020-01-22 14:34

You can handle it by logic alone too, although I have to admit that the suggestions above where you end up with a BringToFront method without actually stealing focus is the most elegant one.

Anyhow, I ran into this and solved it by using a DateTime property to not allow further BringToFront calls if calls were made already recently.

Assume a core class, 'Core', which handles for example three forms, 'Form1, 2, and 3'. Each form needs a DateTime property and an Activate event that call Core to bring windows to front:

internal static DateTime LastBringToFrontTime { get; set; }

private void Form1_Activated(object sender, EventArgs e)
{
    var eventTime = DateTime.Now;
    if ((eventTime - LastBringToFrontTime).TotalMilliseconds > 500)
        Core.BringAllToFront(this);
    LastBringToFrontTime = eventTime;
}

And then create the work in the Core Class:

internal static void BringAllToFront(Form inForm)
{
    Form1.BringToFront();
    Form2.BringToFront();
    Form3.BringToFront();
    inForm.Focus();
}

On a side note, if you want to restore a minimized window to its original state (not maximized), use:

inForm.WindowState = FormWindowState.Normal;

Again, I know this is just a patch solution in the lack of a BringToFrontWithoutFocus. It is meant as a suggestion if you want to avoid the DLL file.

查看更多
放我归山
5楼-- · 2020-01-22 14:36

Figured it out: window.WindowState = WindowState.Minimized;.

查看更多
混吃等死
6楼-- · 2020-01-22 14:37

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.

查看更多
登录 后发表回答