当特定事件在C# / WPF中发生时,强制窗口闪烁

14

我正在使用C# / WPF制作一个应用程序。在该应用程序中,如果发生特定事件,我想让窗口闪烁,以便该应用程序的用户知道发生了什么事情。如何在我的C# WPF应用程序中实现这个效果。

就像在Yahoo Messenger中,如果你收到一条消息,那么消息窗口会闪烁以引起你的注意,我想在我的应用程序中使用这种效果。


我刚接触 WPF,在谷歌上搜索了一下,但没有找到任何容易理解的简单解决方案。 - Aqeel
@Marco 那个链接展示了如何让任务栏中的窗口闪烁,而不是如何让一个普通大小的窗口闪烁。 - Rachel
3个回答

31

使用以下代码可以在 WPF 中以类似 IM 通知的方式闪烁窗口和任务栏。它使用 PlatformInvoke 调用 WinAPI 函数 FlashWindowEx,并使用 WPF Application.Current.MainWindow 的 Win32 句柄。

代码

public class FlashWindowHelper
{
    private IntPtr mainWindowHWnd;
    private Application theApp;

    public FlashWindowHelper(Application app)
    {
        this.theApp = app;
    }

    public void FlashApplicationWindow()
    {
        InitializeHandle();
        Flash(this.mainWindowHWnd, 5);
    }

    public void StopFlashing()
    {
        InitializeHandle();

        if (Win2000OrLater)
        {
            FLASHWINFO fi = CreateFlashInfoStruct(this.mainWindowHWnd, FLASHW_STOP, uint.MaxValue, 0);
            FlashWindowEx(ref fi);
        }
    }

    private void InitializeHandle()
    {
        if (this.mainWindowHWnd == IntPtr.Zero)
        {
            // Delayed creation of Main Window IntPtr as Application.Current passed in to ctor does not have the MainWindow set at that time
            var mainWindow = this.theApp.MainWindow;
            this.mainWindowHWnd = new System.Windows.Interop.WindowInteropHelper(mainWindow).Handle;
        }
    }

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

    [StructLayout(LayoutKind.Sequential)]
    private 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 uint dwFlags;
        /// <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;
    }

    /// <summary>
    /// Stop flashing. The system restores the window to its original stae.
    /// </summary>
    public const uint FLASHW_STOP = 0;

    /// <summary>
    /// Flash the window caption.
    /// </summary>
    public const uint FLASHW_CAPTION = 1;

    /// <summary>
    /// Flash the taskbar button.
    /// </summary>
    public const uint FLASHW_TRAY = 2;

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

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

    /// <summary>
    /// Flash continuously until the window comes to the foreground.
    /// </summary>
    public const uint FLASHW_TIMERNOFG = 12;

    /// <summary>
    /// Flash the spacified Window (Form) until it recieves focus.
    /// </summary>
    /// <param name="hwnd"></param>
    /// <returns></returns>
    public static bool Flash(IntPtr hwnd)
    {
        // Make sure we're running under Windows 2000 or later
        if (Win2000OrLater)
        {
            FLASHWINFO fi = CreateFlashInfoStruct(hwnd, FLASHW_ALL | FLASHW_TIMERNOFG, uint.MaxValue, 0);

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

    private static FLASHWINFO CreateFlashInfoStruct(IntPtr handle, uint flags, uint count, uint timeout)
    {
        FLASHWINFO fi = new FLASHWINFO();
        fi.cbSize = Convert.ToUInt32(Marshal.SizeOf(fi));
        fi.hwnd = handle;
        fi.dwFlags = flags;
        fi.uCount = count;
        fi.dwTimeout = timeout;
        return fi;
    }

    /// <summary>
    /// Flash the specified Window (form) for the specified number of times
    /// </summary>
    /// <param name="hwnd">The handle of the Window to Flash.</param>
    /// <param name="count">The number of times to Flash.</param>
    /// <returns></returns>
    public static bool Flash(IntPtr hwnd, uint count)
    {
        if (Win2000OrLater)
        {
            FLASHWINFO fi = CreateFlashInfoStruct(hwnd, FLASHW_ALL | FLASHW_TIMERNOFG, count, 0);

            return FlashWindowEx(ref fi);
        }            

        return false;
    }

    /// <summary>
    /// A boolean value indicating whether the application is running on Windows 2000 or later.
    /// </summary>
    private static bool Win2000OrLater
    {
        get { return Environment.OSVersion.Version.Major >= 5; }
    }
}

用法

var helper = new FlashWindowHelper(Application.Current);

// Flashes the window and taskbar 5 times and stays solid 
// colored until user focuses the main window
helper.FlashApplicationWindow(); 

// Cancels the flash at any time
helper.StopFlashing();

这是一个很好的例子.. 但对我来说,任务栏图标只闪烁了不到一秒钟 :( - Julien
2
值得注意的是,这适用于多个版本的Windows(而不仅仅是其他答案中提到的 TaskBarItem/System.Windows.Shell 等Win 7 (+later?) 版本)。 - David
@Dr.ABT 在我的应用程序中,“this.mainWindowHWnd = new System.Windows.Interop.WindowInteropHelper(mainWindow).Handle”将属性设置为0。我错过了什么? - Chrisjan Lodewyks
真抱歉,我不知道。我是三年前写的,而且早已离开了这个项目!... - Dr. Andrew Burnett-Thompson
我也遇到了任务栏只闪烁一次的问题。这个解决方案似乎有效:https://dev59.com/OG435IYBdhLWcg3w9FBY#5118285 - Bryan Matthews
显示剩余2条评论

7
你可以使用 TaskBarItem 类来使你的应用程序任务栏图标闪烁。 这里 有一些可以帮助你实现它的东西。
然后,你可以使用 WPF 动画闪烁、摇晃、淡入淡出或其他无数的特效。如果你有 Expression Blend,那么这项工作就更容易了,非常简单,几乎不需要编写代码。

我只想让WPF窗口闪烁,而不想显示进度。我使用了这段代码,但它并没有帮助我完成任务。你能否简单地告诉我如何在特定事件(无论是点击按钮还是在特定时间)下让WPF窗口闪烁? - Aqeel
答案已更新。我没有提到进度条,你可以让任务栏图标闪烁自身,除了窗口闪烁之外。 - Shimmy Weitzhandler
1
一些链接已经失效,请修复它们。 - Rand Random

5

这不会闪烁,而是显示一个“波浪”动画,对应于一个未知进度的操作。 - Error404

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接