Avalonia에서 C#을 사용하여 Arch Linux에서 트레이 아이콘을 해결하고 UI 문제를 최소화하는 Touch001

내 프로젝트의 기능에 대해 생각하기 시작했을 때 사용자가 응용 프로그램을 최소화할 때 작업 표시줄에서 숨겨야 한다는 생각이 들었고 깊이 생각했을 때 숨기는 것만으로는 충분하지 않다는 것을 알았습니다. 사용자는 어떻게든 숨겨진 애플리케이션에서 돌아올 수 있어야 합니다. 그리고 해결책은 트레이 아이콘을 갖는 것입니다. Windows에서는 항상 오른쪽의 작업 표시줄에 있으며 네트워크 또는 볼륨과 같은 일부 트레이 아이콘을 찾을 수 있습니다. Linux에서도 작동하는지 궁금합니다. 저는 Endeavour를 Plasma 플레이버와 함께 사용하고 있기 때문에 어떻게든 가능해야 한다는 것을 알았지만 Avalonia 프레임워크가 이를 지원하는지 확신할 수 없었습니다. 나는이 문제를 봤고이 문제를 해결하는 일부 git 프로젝트가 있음을 발견했습니다. 그래서 IDE를 열고 코드를 작성하기로 했습니다. 먼저 나는 그것이 더 쉬울 것이라고 생각했기 때문에 최소화 문제로 시작했습니다. 이 코딩을 시작했을 때 그렇게 쉽지 않을 것이라는 것을 쉽게 알았습니다. 그래서 공식 Avalonia Sources에서 첫 번째 문제에 대해 조금 검색했습니다. MainWindow에서 PropertyChanged 이벤트에 등록하고 내 특정 속성을 필터링한 다음 MainWindow를 숨길 수 있는 방식으로 할 수 있다는 것을 알게 되었습니다. 그래서 나는 다음과 같이 시도했다.

private void MyMainWindow_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
    if (sender is MainWindow && e.NewValue is WindowState windowState && windowState == WindowState.Minimized)
    {
        myMainWindow?.Hide();
    }
}


이와 같이 더 쉬운 솔루션이 있어야한다고 느꼈습니다. 그래서 조금 더 구글링을 했습니다. 나는 그것을 시도할 수 있는 방법에 대한 Avalonion Gitter 게시물을 찾은 10페이지쯤에 Google에서 끝났습니다. 게시물은 HandleWindowStateChanged 메서드 재정의에 대해 설명했습니다. 그래서 해봤더니 제대로 되네요. 그래서 Endeavour Linux에서 시도해 보았고 쉽게 알아냈습니다. Linux에서 작업 표시줄 아이콘은 최소화 후에도 숨겨지지 않습니다. 또한 Windows 및 Linux에서 몇 가지 결함을 보았습니다. MainWindow로 돌아왔을 때 제대로 표시되지 않았습니다. 같은 게시물에서 몇 가지 메서드 호출을 제안했습니다. 나는 그것을 시도했고 두 플랫폼 모두에서 작동했습니다. Minimalize, Hide app 및 Hide Icon Bar에 대한 최종 코드는 아래와 같습니다. 언젠가 누군가에게 도움이 될 것입니다.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    protected override void HandleWindowStateChanged(WindowState state)
    {
        if (state == WindowState.Minimized)
        {
            ShowInTaskbar = false;
            Hide();
        }

        if(state == WindowState.Normal)
        {
            ShowInTaskbar = true;
            this.BringIntoView();
            Activate();
            Focus();
            base.HandleWindowStateChanged(state);
        }
    }
}


지금은 이 동작에 대한 테스트를 작성하는 방법을 모르지만 최소한 다음 Touch 기사가 될 수 있습니다.

이 시점에서 아직 트레이 아이콘에 대한 솔루션을 구현하지 않았습니다. 아발로니아 공식 웹페이지에서 아발로니아가 이미 트레이 아이콘을 지원한다는 것을 알았으므로 git의 일부 솔루션을 사용할 필요가 없습니다. 그러나 불행하게도 이것을 사용하는 방법에 대한 문서나 위키가 없었습니다. 그래서 실험해봤습니다.

결국 나는 이것과 비슷한 코드를 가졌습니다.

public partial class App : Application
{
    private MainWindow? myMainWindow;

    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;

            RegisterTrayIcon();
        }

        base.OnFrameworkInitializationCompleted();
    }

    private void RegisterTrayIcon()
    {
        var trayIcon = new TrayIcon
        {
            IsVisible = true,
            ToolTipText = "TestToolTipText",
            Command = ReactiveCommand.Create(ShowApplication),
            Icon = new WindowIcon("/Assets/avalonia-logo.ico")
        };
    }

    private void ShowApplication()
    {
        if(myMainWindow != null)
        {
            myMainWindow.WindowState = WindowState.Normal;
            myMainWindow.Show();
        }
    }
}


그리고 그것은 작동하지 않았습니다. 아래와 같이 손쉬운 명령 생성을 위해 ReactiveUI 라이브러리도 사용했습니다.

Command = ReactiveCommand.Create(ShowApplication),


또한 사용자가 트레이 아이콘을 클릭할 때 발생하는 동작을 구현하여 애플리케이션을 다시 표시합니다.

private void ShowApplication()
{
    if(myMainWindow != null)
    {
        myMainWindow.WindowState = WindowState.Normal;
        myMainWindow.Show();
    }
}


아이콘을 로드할 때 런타임 중에 실패했습니다. 나는 이것을 위해 .ico를 사용할 수 없지만 투명한 png 이미지를 사용할 수 있다는 것을 알아 냈습니다. 그래서 Bitmap으로 로드한 다음 WindowIcon을 만들어야 했습니다. 그래서 이 줄을 아래 코드로 대체했습니다.

Icon = new WindowIcon(new Bitmap("C:/Icons/test.png"))


이 변경 후 코드가 올바르게 작동했습니다. 앱이 숨어 있었는데 트레이 아이콘을 클릭하면 다시 표시되었습니다. 하지만 응용 프로그램을 닫을 때 닫는 동안 실패했습니다. 운 좋게도이 순간에 발생한 예외는이 문제를 해결하는 데 도움이되었습니다. Attached 속성으로 Tray Icon 값을 설정하지 않았다는 것입니다. 그래서 구현했고 네, 두 플랫폼 모두에서 예상대로 작동합니다.

따라서 최종 코드는 아래와 같습니다. 기사 아래에 자유롭게 사용하고 의견을 말하십시오. 이것에 대해 어떻게 생각하세요?

public partial class App : Application
{
    private MainWindow? myMainWindow;

    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;

            RegisterTrayIcon();
        }

        base.OnFrameworkInitializationCompleted();
    }

    private void RegisterTrayIcon()
    {
        var trayIcon = new TrayIcon
        {
            IsVisible = true,
            ToolTipText = "TestToolTipText",
            Command = ReactiveCommand.Create(ShowApplication),
            Icon = new WindowIcon(new Bitmap("C:/Icons/test.png"))
        };

        var trayIcons = new TrayIcons
        {
            trayIcon
        };

        SetValue(TrayIcon.IconsProperty, trayIcons);
    }

    private void ShowApplication()
    {
        if(myMainWindow != null)
        {
            myMainWindow.WindowState = WindowState.Normal;
            myMainWindow.Show();
        }
    }
}

좋은 웹페이지 즐겨찾기