10

I have a program that lets the user open several forms. Once a given event occurs (ex : 30 seconds have passed) I need to get user attention on the Form that triggered the event, without stealing the focus. I already get the form on top with:

f.TopMost = true;

but I'd like to implement some alternative to that. Since changing the border color of the frame seems a nearly impossible task ( this solution would have been the best one), does anyone has an idea on how to get attention without stealing focus?

ag93
  • 343
  • 4
  • 17
kaharas
  • 597
  • 2
  • 17
  • 39

2 Answers2

20

Option A: You need to use FlashWindowEx from the windows API. This isn't available in .NET, so you need to use PInvoke.

Option B: Use a balloon tip from the system tray. This is built into .NET, but requires that your application use a notification icon, which you might not want. More details here: http://msdn.microsoft.com/en-us/library/system.windows.forms.notifyicon.showballoontip.aspx

Here is the example for how to use Option A:

pInvoke.net has the best example: http://pinvoke.net/default.aspx/user32.FlashWindowEx

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FlashWindowEx(ref FLASHWINFO pwfi);

User-Defined Types:

[StructLayout(LayoutKind.Sequential)]
public struct FLASHWINFO
{
    public UInt32 cbSize;
    public IntPtr hwnd;
    public UInt32 dwFlags;
    public UInt32 uCount;
    public UInt32 dwTimeout;
}

Notes:

//Stop flashing. The system restores the window to its original state. 
public const UInt32 FLASHW_STOP = 0; 
//Flash the window caption. 
public const UInt32 FLASHW_CAPTION = 1; 
//Flash the taskbar button. 
public const UInt32 FLASHW_TRAY = 2; 
//Flash both the window caption and taskbar button.
//This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags. 
public const UInt32 FLASHW_ALL = 3; 
//Flash continuously, until the FLASHW_STOP flag is set. 
public const UInt32 FLASHW_TIMER = 4; 
//Flash continuously until the window comes to the foreground. 
public const UInt32 FLASHW_TIMERNOFG = 12;

Tips & Tricks:

Please add some!

Sample Code:

/// <summary>
/// Flashes a window
/// </summary>
/// <param name="hWnd">The handle to the window to flash</param>
/// <returns>whether or not the window needed flashing</returns>
public static bool FlashWindowEx(IntPtr hWnd)
{
    FLASHWINFO fInfo = new FLASHWINFO();

    fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
    fInfo.hwnd = hWnd;
    fInfo.dwFlags = FLASHW_ALL;
    fInfo.uCount = UInt32.MaxValue;
    fInfo.dwTimeout = 0;

    return FlashWindowEx(ref fInfo);
}

...

/// Minor adjust to the code above
/// <summary>
/// Flashes a window until the window comes to the foreground
/// Receives the form that will flash
/// </summary>
/// <param name="hWnd">The handle to the window to flash</param>
/// <returns>whether or not the window needed flashing</returns>
public static bool FlashWindowEx(Form frm)
{
        IntPtr hWnd = frm.Handle;
        FLASHWINFO fInfo = new FLASHWINFO();

        fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo));
        fInfo.hwnd = hWnd;
        fInfo.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG;
        fInfo.uCount = UInt32.MaxValue;
        fInfo.dwTimeout = 0;

        return FlashWindowEx(ref fInfo);
}

Here is the official Microsoft example: http://msdn.microsoft.com/en-us/library/ms679347(v=vs.85).aspx

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool FlashWindowEx(ref FLASHWINFO pwfi);

    [StructLayout(LayoutKind.Sequential)]
    public struct FLASHWINFO
    {
        /// <summary>
        /// The size of the structure in bytes.
        /// </summary>
        public uint cbSize;
        /// <summary>
        /// A Handle to the Window to be Flashed. The window can be either opened or minimized.
        /// </summary>
        public IntPtr hwnd;
        /// <summary>
        /// The Flash Status.
        /// </summary>
        public FlashWindowFlags dwFlags; //uint
        /// <summary>
        /// The number of times to Flash the window.
        /// </summary>
        public uint uCount;
        /// <summary>
        /// The rate at which the Window is to be flashed, in milliseconds. If Zero, the function uses the default cursor blink rate.
        /// </summary>
        public uint dwTimeout;
    }


    public enum FlashWindowFlags : uint
    {
        /// <summary>
        /// Stop flashing. The system restores the window to its original state.
        /// </summary>
        FLASHW_STOP = 0,

        /// <summary>
        /// Flash the window caption.
        /// </summary>
        FLASHW_CAPTION = 1,

        /// <summary>
        /// Flash the taskbar button.
        /// </summary>
        FLASHW_TRAY = 2,

        /// <summary>
        /// Flash both the window caption and taskbar button.
        /// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags.
        /// </summary>
        FLASHW_ALL = 3,

        /// <summary>
        /// Flash continuously, until the FLASHW_STOP flag is set.
        /// </summary>
        FLASHW_TIMER = 4,

        /// <summary>
        /// Flash continuously until the window comes to the foreground.
        /// </summary>
        FLASHW_TIMERNOFG = 12
    }


    public static bool FlashWindow(IntPtr hWnd, 
                                   FlashWindowFlags fOptions, 
                                   uint FlashCount, 
                                   uint FlashRate)
    {
        if(IntPtr.Zero != hWnd)
        {
            FLASHWINFO fi = new FLASHWINFO();
            fi.cbSize = (uint)Marshal.SizeOf(typeof(FLASHWINFO));
            fi.dwFlags = fOptions;
            fi.uCount = FlashCount;
            fi.dwTimeout = FlashRate;
            fi.hwnd = hWnd;

            return FlashWindowEx(ref fi);
        }
        return false;
    }

    public static bool StopFlashingWindow(IntPtr hWnd)
    {
        if(IntPtr.Zero != hWnd)
        {
            FLASHWINFO fi = new FLASHWINFO();
            fi.cbSize = (uint)Marshal.SizeOf(typeof(FLASHWINFO));
            fi.dwFlags = (uint)FlashWindowFlags.FLASHW_STOP;
            fi.hwnd = hWnd;

            return FlashWindowEx(ref fi);
        }
        return false;
    }
tster
  • 17,883
  • 5
  • 53
  • 72
  • Good call on using `NotifyIcon`! – Jeff B Oct 18 '12 at 14:47
  • Important: On Windows 7 some users reported this as Not working. After some research, I've found the reason being that if your application has multiple windows and if any of those windows is active while you call this API to flash another window, it won't work. It will only work if all windows in your program are inactive. If you are stuck in first scenario then use older api FlashWindow: http://pinvoke.net/default.aspx/user32/FlashWindow.html – tunafish24 Oct 26 '15 at 20:00
7

In Windows 7, a progress bar on a form is represented in its taskbar button; you might leverage that. There's also got to be a way to simply highlight the taskbar button, like IM programs do when you get a new message.

KeithS
  • 70,210
  • 21
  • 112
  • 164
  • I would love to see how to simply highlight the taskbar button instead of flashing it... having trouble finding good code samples that do that. – Jeff B Oct 18 '12 at 14:46
  • Using FlashWindow with a Count set to 0 may just mark the taskbar item orange without flashing it. – Bill Tarbell Sep 09 '21 at 19:33