I know similar questions have been asked many times but I have not been able to find anything that works in this situation. I have an application that runs minimized to the taskbar using wpf-notifyicon. The main window opens, authenticates and is then hidden. A process runs in the background and I would like it to send updates to the main thread. Most of the time it works. However, the taskbar icon has a context menu that allows the user to open application settings. If I open then close the settings window, the next time I try to update the balloon, I get a a null reference error System.NullReferenceException: 'Object reference not set to an instance of an object.' System.Windows.Application.MainWindow.get returned null.
It's like once I open another window, the main window is lost and I can't figure out how to find it again.
This is how I am updating the balloon. This code is in a notification service and is called from inside the MainWindow View Model and from inside other services.
// Show balloon update on the main thread
Application.Current.Dispatcher.Invoke( new Action( () =>
{
var notifyIcon = ( TaskbarIcon )Application.Current.MainWindow.FindName( "NotifyIcon" );
notifyIcon.ShowBalloonTip( title, message, balloonIcon );
} ), DispatcherPriority.Normal );
The notification icon is declared inside the XAML for the main window.
<tb:TaskbarIcon
x:Name="NotifyIcon"
IconSource="/Resources/Icons/card_16x16.ico"
ToolTipText="Processor"
MenuActivation="LeftOrRightClick"
DoubleClickCommand="{Binding ShowStatusCommand}">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu>
<MenuItem Header="Settings" Command="{Binding ShowSettingsCommand}" />
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
<tb:TaskbarIcon.TrayToolTip>
<Border Background="Gray"
BorderBrush="DarkGray"
BorderThickness="1"
CornerRadius="3"
Opacity="0.8"
Width="180"
Height="20">
<TextBlock Text="{Binding ListeningMessage }" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</tb:TaskbarIcon.TrayToolTip>
</tb:TaskbarIcon>
How can I safely update the balloon icon from background threads?
Update 1:
The context menu is bound to commands in the view model. To open the settings window
<ContextMenu>
<MenuItem Header="Settings" Command="{Binding ShowSettingsCommand}" />
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
</ContextMenu>
The command in the VM is:
public ICommand ShowSettingsCommand => new DelegateCommand
{
CommandAction = () =>
{
Application.Current.MainWindow = new Views.SettingsWindow( _logger, _hidservice, _certificateService );
Application.Current.MainWindow.Show();
}
};
To close the settings window, I have an action in the window code behind
public ICommand CancelSettingsCommand => new DelegateCommand
{
CommandAction = () => CloseAction()
};
// In Code Behind
vm.CloseAction = new Action( () => this.Close() );
You are overriden the main window. You should not do that. Just create a new instance of it and call
Show()
.