Caliburn Micro с NotifyIcon.WPF, несколькими иконками в трее и неудачной привязкой
Я пытаюсь заставить WPF NotifyIcon Hardcodet работать в приложении WPF и получаю странные результаты.
Цель состоит в следующем:
- MainViewModel получает уведомление от EventAggregator
- MainViewModel использует ShowBaloonTip для отображения уведомлений
Используемые библиотеки:
- Caliburn.Micro
- Hardcodet.NotifyIcon.WPF
- Autofac
- Caliburn.Micro.AutofacBootstrap
- MaterialDesignThemes
Во-первых, я хотел опубликовать реализацию NotifyIcon, которая не имеет реализации BalloonTip. Это прекрасно работает, никаких проблем здесь:
MainView.xaml
<Window.Resources>
<ContextMenu x:Shared="false" x:Key="MainSysTrayMenu">
<MenuItem Header="Quick Status" cal:Message.Attach="OpenStatusWindow()" IsEnabled="{Binding Path=CanOpenStatusWindow, Mode=OneWay}" />
<MenuItem Header="Details" cal:Message.Attach="OpenDetailWindow()" IsEnabled="{Binding Path=CanOpenDetailWindow, Mode=OneWay}" />
<MenuItem Header="About" cal:Message.Attach="OpenAboutWindow()" IsEnabled="{Binding Path=CanOpenAboutWindow, Mode=OneWay}" />
<Separator />
<MenuItem Header="Exit" cal:Message.Attach="ExitApplication()" />
</ContextMenu>
<tb:TaskbarIcon x:Key="SystemTrayIcon"
IconSource="/Resources/NotifyIcons/Red.ico"
ToolTipText="Double-click for window, right-click for menu"
cal:Message.Attach="[Event TrayMouseDoubleClick] = [Action OpenStatusWindow]"
Visibility="Visible"
ContextMenu="{StaticResource MainSysTrayMenu}" >
<tb:TaskbarIcon.TrayToolTip>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
Background="White"
BorderBrush="DeepSkyBlue"
BorderThickness="2"
CornerRadius="4"
Opacity="0.95"
Width="165"
Height="40">
<TextBlock Text="{Binding Path=StatusToolTipText, Mode=OneWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="Black"
FontFamily="{DynamicResource MaterialDesignFont}"
/>
</Border>
</Grid>
</tb:TaskbarIcon.TrayToolTip>
</tb:TaskbarIcon>
</Window.Resources>
<Grid>
<TextBlock>View + ViewModel started from bootstrapper. This should not be visible.</TextBlock>
<ContentControl >
<Label x:Name="TestString" Content="Label" HorizontalAlignment="Left" Margin="111,83,0,0" VerticalAlignment="Top"/>
</ContentControl>
<ContentControl Content="{StaticResource SystemTrayIcon}" />
</Grid>
MainViewModel
public MainViewModel(IWindowManager windowManager, IEventAggregator eventAggregator, StatusViewModel statusViewModel,
DetailViewModel detailViewModel, AboutViewModel aboutViewModel)
{
_windowManager = windowManager;
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);
_statusViewModel = statusViewModel;
_detailViewModel = detailViewModel;
_aboutViewModel = aboutViewModel;
_statusToolTipText = "SOC: 0% | RTE: 0min";
LaunchManager();
}
И вспомогательные функции ViewModel, используемые в MainView
public bool CanOpenStatusWindow => !_statusViewModel.IsActive;
public bool CanCloseStatusWindow => _statusViewModel.IsActive;
public void OpenStatusWindow()
{
_windowManager.ShowWindow(_statusViewModel);
NotifyOfPropertyChange(() => CanOpenStatusWindow);
NotifyOfPropertyChange(() => CanCloseStatusWindow);
}
Это дублируется для каждого из трех окон, довольно стандартно.
NotifyIcon "MVVM" реализация
Здесь все становится сложнее. В примере кода из Hardcodet привязка выполняется следующим образом:
<tb:TaskbarIcon IconSource="/Icons/Inactive.ico"
ToolTipText="{Binding Timestamp}">
<tb:TaskbarIcon.TrayPopup >
<!-- the popup, here a custom user control, will also get the DataContext of the NotifyIcon -->
<local:ClockPopup Opacity="0.8" />
</tb:TaskbarIcon.TrayPopup>
</tb:TaskbarIcon>
Мое намерение состояло в том, чтобы Связать этот TaskbarIcon с NotifyIcon. Мне не удалось заставить реализацию работать со StaticResource, поэтому я перенес весь кусок на страницу MainWindow.xaml:
MainView.xaml
<tb:TaskbarIcon x:Name="NotifyIcon"
IconSource="/Resources/NotifyIcons/Red.ico"
ToolTipText="Double-click for window, right-click for menu"
cal:Message.Attach="[Event TrayMouseDoubleClick] = [Action OpenStatusWindow]"
Visibility="Visible">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu DataContext="{Binding}">
<MenuItem Header="Quick Status" cal:Message.Attach="OpenStatusWindow()" IsEnabled="{Binding Path=CanOpenStatusWindow, Mode=OneWay}" />
<MenuItem Header="Details" cal:Message.Attach="OpenDetailWindow()" IsEnabled="{Binding Path=CanOpenDetailWindow, Mode=OneWay}" />
<MenuItem Header="About" cal:Message.Attach="OpenAboutWindow()" IsEnabled="{Binding Path=CanOpenAboutWindow, Mode=OneWay}" />
<Separator />
<MenuItem Header="Exit" cal:Message.Attach="ExitApplication()" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
<tb:TaskbarIcon.TrayToolTip>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
Background="White"
BorderBrush="DeepSkyBlue"
BorderThickness="2"
CornerRadius="4"
Opacity="0.95"
Width="165"
Height="40">
<TextBlock Text="{Binding Path=StatusToolTipText, Mode=OneWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="Black"
FontFamily="{DynamicResource MaterialDesignFont}"
/>
</Border>
</Grid>
</tb:TaskbarIcon.TrayToolTip>
</tb:TaskbarIcon>
MainViewModel.xaml
private NotifyIcon _notifyIcon;
public NotifyIcon NotifyIcon
{
get => _notifyIcon;
set
{
_notifyIcon = value;
NotifyOfPropertyChange();
}
}
public MainViewModel(IWindowManager windowManager, IEventAggregator eventAggregator,
StatusViewModel statusViewModel,
DetailViewModel detailViewModel, AboutViewModel aboutViewModel)
{
_notifyIcon = new NotifyIcon();
_notifyIcon.BalloonTipText = "test";
_notifyIcon.ShowBalloonTip(3000);
}
Следующее не сработало, поэтому я попробовал парную реализацию, которую нашел на сайте, но безрезультатно. Эта страница: Как интегрировать WPF NotifyIcon с Caliburn.Micro не работает из-за его старшего возраста (NotifyIcon - это использование, которое они рекомендуют в документации, а не TaskbarIcon). Запуск программы вызвал зацикливание, открывающее множество значков в трее.
Правильное создание экземпляра _notifyIcon с иконкой, контекстным меню и текстом фактически привело к созданию двух панелей задач. Одна с моей хорошей панелью задач и меню, другая с той, что сделана во ViewModel.
Буду признателен за любую помощь, моя единственная цель - сохранить меню, как оно определено в MaterialView.xaml, но иметь возможность запускать уведомления BallonTip для разных состояний соединения и т. Д.
Спасибо за помощь и прочитав все это, я дал ему около 3 дней проб и ошибок, но безрезультатно.