WPF NotifyIcon Ссылка на TaskbarIcon (без окон)

Я новичок в WPF NotifyIcon, и я пытаюсь использовать пример без окон, который использует ResourceDictionary вместо окна, и TaskbarIcon.DataContext установлен на мой ViewModel. Я могу вызвать пример команды (ShowWindowCommand и т. Д.), И она отлично работает.

Тем не менее, в моей ViewModel я не могу понять, как ссылаться на TaskbarIcon. Я хочу показать стандартный всплывающее окно что-то вроде NotifyIcon.ShowBallonTip(title, text, BalloonIcon.Error). Я попытался дать tb:TaskbarIcon x:Name, но моя ViewModel все еще не видит его.

Как мне ссылаться на TaskbarIcon из моей ViewModel? Спасибо!

 <tb:TaskbarIcon x:Key="NotifyIcon"
                IconSource="/Red.ico"
                ToolTipText="Double-click for window, right-click for menu"
                DoubleClickCommand="{Binding ShowWindowCommand}"
                ContextMenu="{StaticResource SysTrayMenu}">

    <tb:TaskbarIcon.DataContext>
        <local:NotifyIconViewModel />
    </tb:TaskbarIcon.DataContext>
</tb:TaskbarIcon>

3 ответа

Решение

Я не уверен, является ли это предпочтительным способом сделать это в ViewModel, но именно так я получил ссылку на TaskbarIcon.

tb = (TaskbarIcon) Application.Current.FindResource ("MyTray");

Вот одна реализация, которая прекрасно работает для меня...

MainWindow.xaml:

xmlns:tb="http://www.hardcodet.net/taskbar"

<tb:TaskbarIcon x:Name="TrayIcon" IconSource="icon.ico" ToolTipText="{Binding TrayIconText}" MenuActivation="RightClick"
    LeftClickCommand="{Binding TrayClickCommand}">
    <tb:TaskbarIcon.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Exit" Command="{Binding CloseAppCommand}" CommandParameter="{Binding}">
                <MenuItem.Icon>
                    <Image Source="pack://application:,,,/Resources/Img/Shutdown32.png" Style="{StaticResource MenuItemImage}"/>
                </MenuItem.Icon>
            </MenuItem>                 
        </ContextMenu>
    </tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>

MainWindow.xaml.cs:

//Subscribe to VM event:
var mvm = DataContext as MainViewModel;
mvm.DisplayTrayBalloonNotice += OnDisplayTrayBalloon;

private void OnDisplayTrayBalloon(object sender, NotificationEventArgs<string> e)
{

    var balloon = new TrayBalloon { NotificationText = e.Data };
    PopupAnimation pa = PopupAnimation.Fade;
    TrayIcon.ShowCustomBalloon(balloon, pa, Settings.Default.NotificationDuration * 1000);
}

TrayBalloon.xaml:

<UserControl x:Class="MCPublisher.Resources.TrayBalloon"
                         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"
                         Height="150" Width="300">
    <UserControl.Resources>
        <Storyboard x:Key="FadeIn">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Grid"
                Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="0.95" />
                <SplineDoubleKeyFrame KeyTime="00:00:03" Value="0.95" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="HighlightCloseButton">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ImgClose"
                Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.4" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="FadeCloseButton">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ImgClose"
                Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0.4" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="FadeBack">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Grid"
                Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="FadeOut" Completed="OnFadeOutCompleted">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Grid"
                Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0.2" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>
    <UserControl.Triggers>
        <EventTrigger RoutedEvent="tb:TaskbarIcon.BalloonShowing">
            <BeginStoryboard Storyboard="{StaticResource FadeIn}" x:Name="FadeInBeginStoryboard" />
        </EventTrigger>
        <EventTrigger RoutedEvent="Mouse.MouseEnter" SourceName="ImgClose">
            <BeginStoryboard Storyboard="{StaticResource HighlightCloseButton}" x:Name="HighlightCloseButtonBeginStoryboard" />
        </EventTrigger>
        <EventTrigger RoutedEvent="Mouse.MouseLeave" SourceName="ImgClose">
            <BeginStoryboard Storyboard="{StaticResource FadeCloseButton}" x:Name="FadeCloseButtonBeginStoryboard" />
        </EventTrigger>
        <EventTrigger RoutedEvent="Mouse.MouseEnter">
            <StopStoryboard BeginStoryboardName="FadeInBeginStoryboard" />
            <BeginStoryboard x:Name="FadeBackBeginStoryboard1" Storyboard="{StaticResource FadeBack}" />
        </EventTrigger>
        <EventTrigger RoutedEvent="tb:TaskbarIcon.BalloonClosing">
            <BeginStoryboard Storyboard="{StaticResource FadeOut}" x:Name="FadeOutBeginStoryboard" />
        </EventTrigger>
    </UserControl.Triggers>
    <Grid x:Name="Grid" MouseEnter="Grid_OnMouseEnter" MouseLeave="Grid_OnMouseLeave">
        <Border x:Name="BnBorder" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="1" CornerRadius="5"
                BorderBrush="{DynamicResource GridView_FilteringControlOuterBorder}"
                Background="{DynamicResource GridView_FilteringControlBackground}">
            <Border.Effect>
                <DropShadowEffect Color="#FF747474" />
            </Border.Effect>
        </Border>
        <Image HorizontalAlignment="Left" Margin="10 10 0 0" Width="64" Height="64" Stretch="Fill" VerticalAlignment="Top"
             Source="{Binding ImageSource}" />
        <TextBlock Margin="84 35 10 0" VerticalAlignment="Top" FontSize="16" FontWeight="Bold" Foreground="#FF575757">
            <Run Text="VHI Notification"/>
        </TextBlock>
        <Path Fill="#FFFFFFFF" Stretch="Fill" Margin="84 60 10 0" VerticalAlignment="Top" Height="1"
                Data="M26,107 L220.04123,107" SnapsToDevicePixels="True">
            <Path.Stroke>
                <LinearGradientBrush EndPoint="0.973,0.5" StartPoint="0.005,0.5">
                    <GradientStop Color="#FF6868FF" Offset="0" />
                    <GradientStop Color="#346868FF" Offset="1" />
                </LinearGradientBrush>
            </Path.Stroke>
        </Path>
        <TextBlock Margin="20 90 10 0" VerticalAlignment="Top" Height="24" TextWrapping="Wrap" FontSize="12" FontWeight="Bold">
            <Run Text="&#x2981; "/>
            <Run Text="{Binding NotificationText}"/>
        </TextBlock>
        <Image x:Name="ImgClose" HorizontalAlignment="Right" Margin="0 10 10 0" VerticalAlignment="Top" Width="16" Height="16"
            Stretch="Fill" Opacity="0.4" ToolTip="Close Balloon" Source="pack://application:,,,/Resources/Img/Exit32.png"
            MouseDown="ImgClose_OnMouseDown" />
    </Grid>
</UserControl>

TrayBalloon.xaml.cs:

public partial class TrayBalloon : UserControl, INotifyPropertyChanged
{
    private bool isClosing;

    public TrayBalloon()
    {
        InitializeComponent();
        DataContext = this;
        TaskbarIcon.AddBalloonClosingHandler(this, OnBalloonClosing);
    }

    private string imageSource;
    public string ImageSource
    {
        get { return imageSource; }
        set
        {
            imageSource = value;
            OnPropertyChanged("ImageSource");
        }
    }

    private string notificationText;
    public string NotificationText
    {
        get { return notificationText; }
        set
        {
            notificationText = value;
            OnPropertyChanged("NotificationText");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void OnBalloonClosing(object sender, RoutedEventArgs e)
    {
        e.Handled = true;
        isClosing = true;
    }


    private void OnFadeOutCompleted(object sender, EventArgs e)
    {
        var pp = (Popup)Parent;
        pp.IsOpen = false;
    }

    private void Grid_OnMouseEnter(object sender, MouseEventArgs e)
    {
        if (isClosing) return;
        var taskbarIcon = TaskbarIcon.GetParentTaskbarIcon(this);
        taskbarIcon.ResetBalloonCloseTimer();
    }

    private void Grid_OnMouseLeave(object sender, MouseEventArgs e)
    {
        if (isClosing) return;
        var taskbarIcon = TaskbarIcon.GetParentTaskbarIcon(this);
        taskbarIcon.CloseBalloon();
    }

    private void ImgClose_OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        var taskbarIcon = TaskbarIcon.GetParentTaskbarIcon(this);
        taskbarIcon.CloseBalloon();
    }
}

В MVVM вы не можете напрямую управлять управлением в вашей виртуальной машине. ВМ не должна ничего знать о View. Вместо этого вы должны определить свойство Icon в VM (как я вижу, это NotifyIconViewModel), а затем в View (TaskbarIcon) вам необходимо привязать его к IconSource.

VM:

public Icon { get { new System.Drawing.Icon(@"..\Properties\Icons\YourIcon.ico"); }};

Посмотреть

<tb:TaskbarIcon DataContext="YourViewModel"
                IconSource="{Binding Path=Icon}"
                ToolTipText="Double-click for window, right-click for menu"
                DoubleClickCommand="{Binding ShowWindowCommand}"
                ContextMenu="{StaticResource SysTrayMenu}"/>
Другие вопросы по тегам