You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF应用开发:如何实现任务栏通知球?附代码片段

嘿,看起来你正在用Hardcodet的WPF TaskbarIcon组件搭建托盘功能,想要实现任务栏托盘图标上的数字通知球(也就是badge标记)对吧?我来给你一步步拆解实现方案~

首先确认一下:你用的<tb:TaskbarIcon>属于Hardcodet.Wpf.TaskbarNotification这个NuGet包,如果还没安装的话,先在NuGet包管理器里搜索安装它,或者用命令行:

Install-Package Hardcodet.Wpf.TaskbarNotification

核心思路:动态生成带数字的托盘图标

Windows原生托盘图标本身不支持直接添加badge标记,所以我们需要自己绘制带数字的图标,替换原有的托盘图标。下面是具体实现步骤:

1. 编写图标生成方法

写一个C#方法,把数字叠加到你的基础图标上,生成新的可用于TaskbarIcon的ImageSource:

private ImageSource GenerateBadgeIcon(ImageSource baseIcon, int badgeNumber)
{
    // 如果没有通知,直接返回原图标
    if (badgeNumber <= 0) return baseIcon;

    // 将基础图标转换为BitmapSource(兼容.ico等格式)
    BitmapSource baseBitmap = baseIcon as BitmapSource;
    if (baseBitmap == null)
    {
        using (var stream = new MemoryStream())
        {
            ((Icon)baseIcon).Save(stream);
            stream.Position = 0;
            var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
            baseBitmap = decoder.Frames[0];
        }
    }

    // 创建可绘制的画布,叠加数字和背景
    var drawingVisual = new DrawingVisual();
    using (var dc = drawingVisual.RenderOpen())
    {
        // 先绘制基础图标
        dc.DrawImage(baseBitmap, new Rect(0, 0, baseBitmap.PixelWidth, baseBitmap.PixelHeight));

        // 计算通知球的尺寸和位置(右上角,大小为图标1/3)
        int badgeSize = Math.Min(baseBitmap.PixelWidth / 3, baseBitmap.PixelHeight / 3);
        Rect badgeRect = new Rect(baseBitmap.PixelWidth - badgeSize, 0, badgeSize, badgeSize);

        // 绘制红色圆形背景(带白色边框)
        dc.DrawEllipse(Brushes.Red, new Pen(Brushes.White, 2), 
            new Point(badgeRect.Left + badgeSize/2, badgeRect.Top + badgeSize/2), 
            badgeSize/2, badgeSize/2);

        // 绘制数字文本(加粗白色,居中)
        var text = new FormattedText(badgeNumber.ToString(),
            CultureInfo.CurrentCulture,
            FlowDirection.LeftToRight,
            new Typeface("Segoe UI Bold"),
            badgeSize * 0.6,
            Brushes.White);
        dc.DrawText(text, new Point(badgeRect.Left + (badgeSize - text.Width)/2, badgeRect.Top + (badgeSize - text.Height)/2));
    }

    // 渲染为BitmapSource返回
    var renderTarget = new RenderTargetBitmap(baseBitmap.PixelWidth, baseBitmap.PixelHeight,
        baseBitmap.DpiX, baseBitmap.DpiY, PixelFormats.Pbgra32);
    renderTarget.Render(drawingVisual);
    return renderTarget;
}

2. 更新托盘图标

当有新通知时,调用上面的方法,把生成的图标赋值给你的TaskbarIcon:

// 示例:假设有5条未读通知
int unreadCount = 5;
var baseIcon = new BitmapImage(new Uri("../Images/icon-one.ico", UriKind.Relative));
IconeDeNotificacao.IconSource = GenerateBadgeIcon(baseIcon, unreadCount);

3. 完善上下文菜单

你的代码里上下文菜单写了一半,这里给你补一个完整的示例,包含常用的“打开应用”和“退出”选项:

<tb:TaskbarIcon x:Name="IconeDeNotificacao" 
                IconSource="../Images/icon-one.ico" 
                ToolTipText="ArquivarNfe" 
                TrayLeftMouseUp="ShowWindow_Click">
    <tb:TaskbarIcon.ContextMenu>
        <ContextMenu>
            <MenuItem Header="打开应用" Click="ShowWindow_Click"/>
            <Separator/>
            <MenuItem Header="退出" Click="ExitApplication_Click"/>
        </ContextMenu>
    </tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>

对应的后台逻辑:

private void ShowWindow_Click(object sender, RoutedEventArgs e)
{
    // 显示并激活主窗口(避免重复创建)
    if (Application.Current.MainWindow == null)
    {
        Application.Current.MainWindow = new MainWindow();
    }
    Application.Current.MainWindow.Show();
    Application.Current.MainWindow.Activate();
}

private void ExitApplication_Click(object sender, RoutedEventArgs e)
{
    // 清理托盘图标后退出应用
    IconeDeNotificacao.Dispose();
    Application.Current.Shutdown();
}

额外提示

如果你的应用是面向Windows 10+的,也可以考虑使用系统Toast通知的Badge功能(显示在任务栏的应用图标上,而非托盘图标),但托盘图标上的数字标记还是自己绘制的方式更通用,兼容更多Windows版本。

内容的提问来源于stack exchange,提问作者Marcos Brinner pikatoons

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:53:02