NotifyIcon-WPF系统托盘图标

NotifyIcon-WPF系统托盘图标

官网:https://www.codeproject.com/Articles/36468/WPF-NotifyIcon-2#wpfapi

NotifyIcon是帮助WPF应用实现系统托盘图标的一个开源库,可以在WPF中,以控件的方式来设置系统托盘图标的工具提示、弹出窗口、上下文菜单和气球消息等。

安装依赖库

在Nuget中直接安装即可:
在这里插入图片描述

基本使用

注意,NotifyIcon可以以XAML或C#代码的方式去实现功能,但无论哪种方式来实现系统托盘图标,其存在时间都是从TaskbarIcon对象的创建,到该对象的消亡或调用了Dispose()方法。当然,作为控件对象,其本身具有Visibility属性,可以通过Visibility来隐藏或显示系统托盘图标。

一、XAML方式(推荐)

做法很简单,只要引入命名空间xmlns:tb="http://www.hardcodet.net/taskbar",然后使用TaskbarIcon控件就可以了。

这里是直接将窗口隐藏了,打开应用后就只有右下角的图标了。

<Window x:Class="NotifyIconTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:tb="http://www.hardcodet.net/taskbar"
        xmlns:local="clr-namespace:NotifyIconTest"
        mc:Ignorable="d" Visibility="Hidden"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" ToolTipText="hello world"/>
    </Grid>
</Window>

NotifyIcon-WPF系统托盘图标_第1张图片

二、代码方式

在代码中,只要创建了TaskbarIcon对象,并进行了响应设置,系统托盘图标就会出现,这里的效果跟上面XAML的方式是一样的。

  • 有一点需要注意的是资源路径的问题,在XAML中实现时,可以将图标属性设置为资源,然后根据程序集的路径来加载的,但如果在代码中实现,那么图标的相对路径是针对当前应用程序所在路径而言的。
TaskbarIcon tbi = new TaskbarIcon();
tbi.Icon = new Icon("bitbug_favicon.ico");
tbi.ToolTipText = "hello world";

三、Xaml+代码

除了上面单独使用XAML或单独使用C#外,当然也可以将两者结合使用,这个就是WPF的基本功了,随便举个用例。
定义资源字典

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:tb="http://www.hardcodet.net/taskbar">
    <tb:TaskbarIcon x:Key="MyNotifyIcon" IconSource="/Icons/bitbug_favicon.ico" ToolTipText="hello world" />
ResourceDictionary>

全局引用

<Application ......>
    <Application.Resources>
        <ResourceDictionary Source="Icons.xaml"/>
    Application.Resources>
Application>

代码获取对象

public partial class MainWindow : Window
{
    private TaskbarIcon _tb;
    public MainWindow()
    {
        InitializeComponent();
        _tb = (TaskbarIcon)FindResource("MyNotifyIcon");
    }
}

进阶使用

很多情况下,仅仅展示个系统托盘图标是不够的,需要给其添加如工具提示、弹出窗口、上下文菜单、气球提示等功能。

一、工具提示

注意:只有当前没有显示其他控件(弹出窗口、上下文菜单或自定义气球提示)时,才会显示工具提示。

TaskbarIcon类中提供了两个与工具提示相关的属性,分别是TrayToolTipToolTipText

TrayToolTip

TrayToolTip属性可以接收任意的UIElement对象,当用户将鼠标悬停在系统托盘图标上时,该元素就会显示出来。可以是一个用户控件,一个按钮,一个图像控件或任何其他控件。

ToolTipText

ToolTipText属性接收一个提示信息的字符串,在以下两种场景下,鼠标悬停在系统托盘图标上时会显式提示信息:

  • TaskbarIconTrayToolTip属性未设置时。
  • 在不支持富工具提示的旧操作系统(xp/2003)上运行应用时。
  • 建议始终设置ToolTipText属性,以便在旧系统上可以保有回退机制。
    在这里插入图片描述

1、内联方式

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
				......>
    <Grid>
        <tb:TaskbarIcon IconSource="/ZoomOut.ico" ToolTipText="ToolTipText">
            <tb:TaskbarIcon.TrayToolTip>
                <Border Background="White" BorderBrush="Orange" BorderThickness="2" CornerRadius="4" Opacity="0.8" Width="160" Height="40">
                    <TextBlock Text="hello world" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Border>
            </tb:TaskbarIcon.TrayToolTip>
        </tb:TaskbarIcon>
    </Grid>
</Window>

NotifyIcon-WPF系统托盘图标_第2张图片

2、用户控件方式

虽然可以以内联的方式完整的定义TrayTToolTip,但当需求复杂,工具提示的内容较多时,更希望能够将工具提示的内容单独分离成用户控件来进行管理,这一点NotifyIcon也是支持的,只需要在xaml中,直接将对应的用户控件作为TrayToolTip的元素即可。

用户控件的定义

<UserControl x:Class="NotifyIconTest.SimpleUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:NotifyIconTest"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Border Background="White" BorderBrush="Orange" BorderThickness="2" CornerRadius="4" Opacity="0.8" Width="160" Height="40">
        <TextBlock Text="hello world" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Border>
</UserControl>

用户控件的使用

<tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" ToolTipText="系统托盘图标测试">
    <tb:TaskbarIcon.TrayToolTip>
        <local:SimpleUserControl/>
    </tb:TaskbarIcon.TrayToolTip>
</tb:TaskbarIcon>

3、资源方式

除了上面两种方式外,还可以将TrayToolTip的内容控件定义为资源,然后在TaskbarIcon控件上以属性的方式来设置TrayToolTip

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
				......>
    <Window.Resources>
        <Border x:Key="trayToolTip" Background="White" BorderBrush="Orange" BorderThickness="2" CornerRadius="4" Opacity="0.8" Width="160" Height="40">
            <TextBlock Text="hello world" HorizontalAlignment="Center" VerticalAlignment="Center" />
        </Border>
    </Window.Resources>
    <Grid>
        <tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" ToolTipText="系统托盘图标测试" TrayToolTip="{StaticResource trayToolTip}"/>
    </Grid>
</Window>

二、弹框

与工具提示不同,默认情况下,弹框只有在鼠标点击系统托盘图标时才会展示,并且在鼠标左键点击其他任意地方时关闭。因此可以在弹框中加入一些应用的快捷方式等交互内容。
NotifyIcon-WPF系统托盘图标_第3张图片

TaskbarIcon类中提供了两个与弹框的相关的属性,分别为TrayPopupPopupActivation

TrayPopup

TrayPopup属性可以接收任意的UIElement对象,默认情况下,在鼠标左键点击系统托盘图标时该UIElement对象就会展现,并且在鼠标左键点击其他任意地方时关闭。

PopupActivation

PopupActivation属性用于设置TrayPopup的触发条件,有效值如下:

  • LeftClick(默认)
  • RightClick
  • DoubleClick
  • LeftOrRightClick
  • LeftOrDoubleClick
  • MiddleClick
  • All

使用

TrayPopup的用法与TrayToolTip的用法完全一样,这里就只做内联方式的演示,其他的可以参考上文TrayToolTip的用法。

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
				......>
    <Grid>
        <tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" ToolTipText="系统托盘图标测试" PopupActivation="LeftOrDoubleClick">
            <tb:TaskbarIcon.TrayPopup>
                <Border Background="White" BorderBrush="Orange" BorderThickness="2" CornerRadius="4" Width="160" Height="80">
                    <StackPanel>
                        <Button Content="开启" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 10" Width="100"/>
                        <Button Content="关闭" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 10" Width="100"/>
                    </StackPanel>
                </Border>
            </tb:TaskbarIcon.TrayPopup>
        </tb:TaskbarIcon>
    </Grid>
</Window>

NotifyIcon-WPF系统托盘图标_第4张图片

三、菜单

默认情况下,当鼠标右键点击系统托盘图标时,可以显示标准的WPF右键菜单。
NotifyIcon-WPF系统托盘图标_第5张图片

TaskbarIcon类中提供了两个与菜单相关的属性,分别为ContextMenuMenuActivation

ContextMenu

ContextMenu属性接收一个WPF的原生ContextMenu控件作为展示内容,跟原生用法是一样的,没啥好说。

MenuActivation

MenuActivation属性用于设置菜单的打开条件,有效值如下:

  • LeftClick
  • RightClick(默认)
  • DoubleClick
  • LeftOrRightClick
  • LeftOrDoubleClick
  • MiddleClick
  • All

注意,如果MenuActivationPopupActivation定义了同样的值,菜单的优先级会高于弹框。

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
        ......>
    <Grid>
        <tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" ToolTipText="系统托盘图标测试">
            <tb:TaskbarIcon.ContextMenu>
                <ContextMenu Background="LightCoral">
                    <MenuItem Header="First Menu Item" />
                    <MenuItem Header="Second Menu Item" />
                </ContextMenu>
            </tb:TaskbarIcon.ContextMenu>
        </tb:TaskbarIcon>
    </Grid>
</Window>

NotifyIcon-WPF系统托盘图标_第6张图片

三、气球提示

NotifyIcon支持两种气球提示,可以使用它们在托盘区域显示信息:

  • 标准气球,由操作系统定义。
  • 自定义气球——就像工具提示和弹出窗口一样,可以把任意的UIElements变成气球消息。这不仅意味着我们可以根据自己的喜好设置气球的样式,而且由于NotifyIcon的丰富事件模型,我们还可以创建精美的动画。

1、标准气球

NotifyIcon-WPF系统托盘图标_第7张图片

要展示标准气球,需要调用TaskbarIcon对象的ShowBalloonTip()方法。

ShowBalloonTip(string title, string message, BalloonIcon symbol):展示标准气球提示。

  • title:标题。
  • message:信息。
  • symbol:标准图标。

ShowBalloonTip(string title, string message, Icon customIcon, bool largeIcon = false)TaskbarIcon的实例方法,展示标准气球提示,可以使用自定义图标。

  • customIcon:自定义图标。
  • largeIcon:是否允许使用大型图标。
  • PS:这里尝试使用了自定义的Icon,发现无法顺利展示气球,不知道是不是当前系统版本(Win10)的原因,用NotifyIcon提供的图标是没问题的。

xaml定义气球的触发事件
这里为了方便,随便搞个事件定义一下,实际情况肯定是根据项目来了

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
				......>
    <Grid>
        <tb:TaskbarIcon x:Name="MyNotifyIcon" IconSource="/Icons/bitbug_favicon.ico" ToolTipText="系统托盘图标测试">
            <tb:TaskbarIcon.TrayPopup>
                <Border Background="White" BorderBrush="Orange" BorderThickness="2" CornerRadius="4" Width="160" Height="80">
                    <Button Content="气球" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 10" Width="100"/>
                Border>
            tb:TaskbarIcon.TrayPopup>
        tb:TaskbarIcon>
    Grid>
Window>

事件的实现

 private void Button_Click(object sender, RoutedEventArgs e)
 {
     MyNotifyIcon.ShowBalloonTip("气球提示", "气球提示内容", BalloonIcon.Warning);
 }

NotifyIcon-WPF系统托盘图标_第8张图片

2、自定义气球

要展示自定义气球,需要调用TaskbarIcon对象的ShowCustomBalloon()方法。

ShowCustomBalloon(UIElement balloon, PopupAnimation animation, int? timeout)TaskbarIcon的实例方法,用于展示自定义气球。

  • balloon:要展示的自定义元素。
  • animation:NotityIcon提供的预定义气球动画。
  • timeout:超时时间(毫秒,且最少要500毫秒),超过时间后关闭气球。

xaml定义气球的触发事件

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
				......>
    <Grid>
        <tb:TaskbarIcon x:Name="MyNotifyIcon" IconSource="/Icons/bitbug_favicon.ico" ToolTipText="系统托盘图标测试">
            <tb:TaskbarIcon.TrayPopup>
                <Border Background="White" BorderBrush="Orange" BorderThickness="2" CornerRadius="4" Width="160" Height="80">
                    <Button Content="气球" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 10" Width="100"/>
                Border>
            tb:TaskbarIcon.TrayPopup>
        tb:TaskbarIcon>
    Grid>
Window>

自定义气球控件的实现

 <UserControl x:Class="NotifyIconTest.SimpleCustomBalloon" ......>
     <Grid>
         <Border Width="100" Height="80" CornerRadius="10" Background="White">
             <Grid>
                 <Grid.ColumnDefinitions>
                     <ColumnDefinition Width="0.4*"/>
                     <ColumnDefinition/>
                 Grid.ColumnDefinitions>
                 <Image Source="/Icons/bitbug_favicon.ico"/>
                 <TextBlock Grid.Column="1" Text="内容展示" VerticalAlignment="Center" HorizontalAlignment="Center"/>
             Grid>
         Border>
     Grid>
 UserControl>

事件的实现

private void Button_Click(object sender, RoutedEventArgs e)
{
    SimpleCustomBalloon customBalloon =new SimpleCustomBalloon();
    MyNotifyIcon.ShowCustomBalloon(customBalloon, PopupAnimation.Slide, 2000);
}

NotifyIcon-WPF系统托盘图标_第9张图片

命令&事件&数据绑定

一、命令

NotifyIcon以较为简洁的方式提供了Command支持,在TaskbarIcon中有LeftClickCommandDoubleClickCommand两个命令属性,可以直接通过绑定表达式与ICommand命令对象进行绑定,也就是用法跟Wpf的Command属性一样的,只不过分为左键点击触发和双击触发。

  • TaskbarIcon中的LeftClickCommandParameterDoubleClickCommandParameter属性可以给两个对应的命令进行设置参数。
  • 此外需要注意的是,LeftClickCommand相对于DoubleClickCommand而言有一个短暂的延时后才触发,这是因为判断是否双击需要有一定的时间间隔。

创建自定义命令

 public class ShowMessageCommand : ICommand
 {
     public event EventHandler? CanExecuteChanged;
 
     public bool CanExecute(object? parameter)
     {
         return true;
     }
 
     public void Execute(object? parameter)
     {
         MessageBox.Show(parameter.ToString());
     }
 }

命令绑定

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
				......>
    <Window.Resources>
        <local:ShowMessageCommand x:Key="ShowMessageCommand"/>
    </Window.Resources>
    <Grid>
        <tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" ToolTipText="系统托盘图标测试" 
                        LeftClickCommand="{StaticResource ShowMessageCommand}" 
                        LeftClickCommandParameter="命令触发成功"/>
    </Grid>
</Window>

NotifyIcon-WPF系统托盘图标_第10张图片

二、数据绑定

TaskbarIcon控件中对其成员使用数据绑定有两种方式,即隐式数据绑定显式数据绑定

1、隐式数据绑定

隐式数据绑定的用法跟原生的WPF数据绑定差不多,也是根据层级查找DataContext,具有以下规则:

  • TaskbarIcon中的子控件进行数据绑定时,会查找自己DataContext中的对应属性,如果本身没有设置DataContext时,会向上层寻找DataContext,在到达TaskbarIcon控件之前,如果找到DataContext,则将其作为自己的DataContext使用。(这里跟原生WPF一样的)
  • 当到达TaskbarIcon控件时,如果TaskbarIcon控件有设置DataContext,就会将DataContext作为TaskbarIcon属性所赋值的控件对象的DataContext,例如下面示例中的TrayToolTip属性所赋值的控件是Border(而不是TextBlock)。
  • 当到达TaskbarIcon控件时,如果TaskbarIcon控件没有设置DataContext,就会将自己作为TaskbarIcon属性所赋值的控件对象的DataContext,例如下面示例中的TrayToolTip属性所赋值的控件是Border(而不是TextBlock)。
<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
        ......>
    <Grid>
        <tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" ToolTipText="数据绑定">
            <tb:TaskbarIcon.TrayToolTip>
                <Border Width="80" Height="50" Background="White">
                    <TextBlock Text="{Binding Path=ToolTipText}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                Border>
            tb:TaskbarIcon.TrayToolTip>
        tb:TaskbarIcon>
    Grid>
Window>

NotifyIcon-WPF系统托盘图标_第11张图片

2、显式数据绑定

显式数据绑定需要通过使用依赖附加属性ParentTaskbarIcon来实现,如果工具提示、弹出窗口、上下文菜单或自定义气球由TaskbarIcon管理,则TaskbarIcon通过此附加属性分配自己。

简单点说,就是TaskbarIcon控件的子控件可以通过TaskbarIcon.ParentTaskbarIcon依赖附加属性来获取TaskbarIcon控件的属性。
实现方式

<Window ......
        xmlns:tb="http://www.hardcodet.net/taskbar"
				......>
    <Grid>
        <tb:TaskbarIcon IconSource="/Icons/bitbug_favicon.ico" DataContext="WPF IS GREAT: " ToolTipText="ToolTipText" >
            <tb:TaskbarIcon.TrayToolTip>
                <Border Width="200" Height="50" Background="White">
                    <TextBlock Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center">
                        <TextBlock Text="{Binding  RelativeSource={RelativeSource Mode=Self},Path=(tb:TaskbarIcon.ParentTaskbarIcon).ToolTipText}" 
                                   HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    TextBlock>
                Border>
            tb:TaskbarIcon.TrayToolTip>
        tb:TaskbarIcon>
    Grid>
Window>

NotifyIcon-WPF系统托盘图标_第12张图片

三、事件

TaskbarIcon中提供了一组路由事件,例如TrayMouseMoveTrayLeftMouseDownTrayToolTipOpen等等很多很多事件,基本上囊括了在NotifyIcon或相关控件中发生的每件事。其使用方式跟原生WPF的事件是一样的,关于怎么使用这些事件实现动画效果的具体细节,可以查看官网的相关示例,这里就不做笔录了。

  • 官网示例:http://www.hardcodet.net/2009/05/trigger-wpf-animations-through-attached-events

你可能感兴趣的:(wpf)