Thank you very much, I doubt I could have gotten this to work if I hadn't found this post. As you mentioned the documentation for this is basically non-existent.
There is however a little mistake in the code in the end (I think?) and a little bit of room for improvement. The little mistake is the window never gets subscribed to the MyMainWindow_PropertyChanged method, so the window never gets hidden from the taskbar.
The little improvement I made is making the icon path non-static, I'm quite new to all of this so there might be a better way to go about loading the icon still but this should works as long as you are working within a Namespace and your project has a /Assets/icon.png in place.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using ReactiveUI;
using System;
using System.Reflection;
namespace PcPunditCrawlerGUI
{
public partial class App : Application
{
private MainWindow? myMainWindow;
private void MyMainWindow_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (sender is MainWindow && e.NewValue is WindowState windowState && windowState == WindowState.Minimized)
{
myMainWindow?.Hide();
}
}
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
myMainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
desktop.MainWindow = myMainWindow;
myMainWindow.PropertyChanged += MyMainWindow_PropertyChanged;
RegisterTrayIcon();
}
base.OnFrameworkInitializationCompleted();
}
private void RegisterTrayIcon()
{
var bitmap = new Bitmap(AvaloniaLocator.Current?.GetService<IAssetLoader>()?.Open(
new Uri($"avares://{Assembly.GetExecutingAssembly().GetName().Name}/Assets/icon.png"))
);
var trayIcon = new TrayIcon
{
IsVisible = true,
ToolTipText = "TestToolTipText",
Command = ReactiveCommand.Create(ShowApplication),
Icon = new WindowIcon(bitmap)
};
var trayIcons = new TrayIcons
{
trayIcon
};
SetValue(TrayIcon.IconsProperty, trayIcons);
}
private void ShowApplication()
{
if (myMainWindow != null)
{
myMainWindow.WindowState = WindowState.Normal;
myMainWindow.Show();
}
}
}
}
That is nice that my article helped someone :) I am working on different thing so my coding hobby went a little bit aside. Yes Avalonia offers multiple ways of loading images, it depends which suits you :)
The problem you mentioned I havent noticed when I played with it :O but indeed it needs to be fixed :)
public partial class App : Application, INotifyPropertyChanged
{
public new event PropertyChangedEventHandler? PropertyChanged;
private MainWindow? _myMainWindow;
private bool _isHidden = false;
public string ShowOrHide{ get => _isHidden ? "Show" : "Hide"; }
private void MyMainWindow_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (sender is MainWindow && e.NewValue is WindowState windowState)
{
if(windowState == WindowState.Minimized)
{
_isHidden = true;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowOrHide)));
_myMainWindow?.Hide();
}
else
{
_isHidden = false;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowOrHide)));
_myMainWindow?.Show();
}
}
}
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
_myMainWindow = new MainWindow{ DataContext = new MainWindowViewModel() };
desktop.MainWindow = _myMainWindow;
_myMainWindow.PropertyChanged += MyMainWindow_PropertyChanged;
DataContext = this;
}
base.OnFrameworkInitializationCompleted();
}
public void ShowOrHideCommand()
{
if (_isHidden)
Show();
else
Hide();
}
public void Show()
{
if (_myMainWindow != null)
{
_myMainWindow.WindowState = WindowState.Normal;
_myMainWindow.Show();
}
}
public void Hide()
{
if(_myMainWindow != null)
{
_myMainWindow.WindowState = WindowState.Minimized;
_myMainWindow.Hide();
}
}
public void Exit()
{
_myMainWindow?.Close();
}
}
Disclaimer: I'm posting this rather late at night right as I got it working, don't know if further propagating the MainWindow.PropertyChanged event is the way to go. It does however work.
Nice work, I was also wondering how to do it in View,(but as I wrote above, currently I do not have time to dive deeply in this topic to understand it complety,) because TrayIcon is UI component :)
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Thank you very much, I doubt I could have gotten this to work if I hadn't found this post. As you mentioned the documentation for this is basically non-existent.
There is however a little mistake in the code in the end (I think?) and a little bit of room for improvement. The little mistake is the window never gets subscribed to the MyMainWindow_PropertyChanged method, so the window never gets hidden from the taskbar.
The little improvement I made is making the icon path non-static, I'm quite new to all of this so there might be a better way to go about loading the icon still but this should works as long as you are working within a Namespace and your project has a /Assets/icon.png in place.
That is nice that my article helped someone :) I am working on different thing so my coding hobby went a little bit aside. Yes Avalonia offers multiple ways of loading images, it depends which suits you :)
The problem you mentioned I havent noticed when I played with it :O but indeed it needs to be fixed :)
I figured out how to do this the MVVM (sort of) way as well - mainly thanks to looking at the code of WalletWasabi (github).
My App.axaml:
And my App.axaml.cs
Disclaimer: I'm posting this rather late at night right as I got it working, don't know if further propagating the MainWindow.PropertyChanged event is the way to go. It does however work.
Nice work, I was also wondering how to do it in View,(but as I wrote above, currently I do not have time to dive deeply in this topic to understand it complety,) because TrayIcon is UI component :)