tags:

views:

12541

answers:

11

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

Thanks for your time. Cheers.

+2  A: 

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.

Matthew Scharley
doesn't seems to work here ... could be because this "notify form" is opened in another thread?
Matías
Probably, in that case you need to do a this.Invoke() call to call the method again as the right thread. Generally working with forms from the wrong thread causes an exception to be thrown though.
Matthew Scharley
+6  A: 

Using pure managed code, no, no there is not. 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)

Alex Lyman
A: 

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.

Fry
+2  A: 

You might want to consider what kind of notification 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 it's 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 sys tray icon.

Silver Dragon
- Balloon tips is not an option because can be disabled- The statusbar could be hidden if you have the program minimizedAnyway thanks for your recomendations
Matías
A: 

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.

Bob Nadler
This will only work if your form was the originally active form. That kind of goes against the main purpose of this kind of notification.
Alex Lyman
Huh? That is the purpose of the notification -- to put it up and regain focus back to the originally active form.
Bob Nadler
This only gives focus to a form in your application -- what if some other program is active at the time? Showing a notification window (usually to give the user an update on your application's status) is only really useful when they're not watching your application.
Alex Lyman
+13  A: 

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

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);
}
TheSoftwareJedi
I was wondering, do he really need that if the form he displays at the lower left of his screen it's in an other thread?
Daok
the threading isn't relevant to receiving focus.
TheSoftwareJedi
I find it unbelievable that we still need to link to external DLL files to interact with forms. We're at .NET framework version 4!! Time to wrap it Microsoft.
Maltrap
+4  A: 

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.

Micah
thanks for the clarification
Matías
+18  A: 

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;

    baseParams.ExStyle |= ( int )( 
      Win32.ExtendedWindowStyles.WS_EX_NOACTIVATE | 
      Win32.ExtendedWindowStyles.WS_EX_TOOLWINDOW );

    return baseParams;
  }
}
Martin Plante
Overriding ShowWithoutActivation worked for me! Thanks a bunch! :)
Helgi Hrafn Gunnarsson
ShowWithoutActivation, Can't believe I didn't find it, wasted one whole afternoon!
deerchao
I also needed to set `form1.Enabled = false` to prevent inner controls from stealing focus
Jader Dias
A: 

This works well:

[System.Runtime.InteropServices.DllImport("user32")]

public static extern long OpenIcon(long hwnd);

[System.Runtime.InteropServices.DllImport("user32")]

public static extern long SetForegroundWindow(long hwnd);


public static void ActivateInstance()
{

    long MyHndl = 0;

    long result = 0;

    Process objProcess = Process.GetCurrentProcess();

    MyHndl = objProcess.MainWindowHandle.ToInt32();

    result = OpenIcon(MyHndl); // Restore the program.

    result = SetForegroundWindow(MyHndl); // Activate the application.

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

}
+1  A: 

hi every body ... thnx for ur great ideas ..

in my case .. this one worked perfectly :

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

(thnx Matthew Scharley)

Hasan
+1  A: 

hi every body ..

i know it may sound stupid .. but this one extremely worked !!!

    this.TopMost = true;
    this.TopMost = false;
    this.TopMost = true;
    this.SendToBack();
Hasan