Aplikacja WPF i ikona w systemowym tray’u

Windows tray’a na pewno każdy zna. Jest to ten obszar paska zadań, w którym widoczne są ikony programów działających w tle. Klikając na nie, możemy łatwo wyświetlić okno danego programu. Nic nie stoi na przeszkodzie, aby klikając na tę samą ikonkę PPM zmienić podstawowe ustawienia programu bez wyświetlania jego okna. Niektóre aplikacje wyświetlają też od czasu do czasu powiadomienia w postaci dymków. Całkiem fajna rzecz. Jak w takim razie się do niej dobrać przy pomocy C#?

WPF i Windows Forms

Pisząc aplikację w technologii WPF musimy zdać sobie sprawę, że przy użyciu wbudowanych bibliotek do systemowego tray’a się nie dobierzemy. Przynajmniej nie przy użyciu metody, którą za chwilę zaprezentuję :P. Czego więc będziemy potrzebowali? Konkretnie referencji do przestrzeni nazw System.Windows.Forms, a więc poprzednika WPF’a:

forms

Kiedy referencja jest podpięta do naszego projektu, możemy wziąć się za pisanie.

Tworzymy klasę do obsługi tray’a

Żeby w kodzie był porządek, stwórzmy prostą klasę, której wywołanie będzie wiązało się ze stworzeniem nowej ikony w systemowym tray’u. Zacznijmy może od konstruktora:

Dlaczego tworzymy tutaj trzy nowe zmienne? Pierwsza z nich typu MainWindow, będzie nam potrzebna do pokazywania okna z poziomu tray’a. Dlatego też jej obiekt jest przyjmowany jako argument w konstruktorze. Kolejne zmienne reprezentują kolejno: menu kontekstowe ikony w tray’u oraz samą ikonę.

W samym konstruktorze tworzymy nowy obiekt klasy NotifyIcon, przypisujemy mu ikonę (w formacie *.ico), która znajduje się w zasobach naszej aplikacji. Następnie ustalamy wyświetlaną w obszarze powiadomień nazwę ikony oraz jej widoczność. Ostatnią rzeczą dotyczącą ikony, jest zdarzenie ni.DoubleClick – które zostaje wywołane po kliknięciu dwa razy LPM na ikonę. W naszym kodzie spowoduje ono wywołanie metody TrayOpen_Click. Za co będzie ona odpowiadać łatwo się domyślić 😉

Kolejna część konstruktora to po prostu dodawanie elementów do menu kontekstowego oraz powiązanie z nimi konkretnych metod. Metody te prezentują się następująco:

Pierwsza zamyka aplikację, druga wyświetla ukryte wcześniej okno aplikacji. Jak z kolei ukryć okno nie zamykając przy tym aplikacji? O tym za chwilę 😉

Zajmijmy się ostatnią rzeczą w tej klasie. Mianowicie powiadomieniami. Do ich wyświetlania stwórzmy taką oto metodę:

Metoda bardzo krótka i prosta. Pozwala na wyświetlanie „dymków” o dowolnej treści i tytule. Po kliknięciu w dymek/powiadomienie zostaniemy przeniesieni do okna naszej aplikacji. Na wytłumaczenie zasługuje chyba tylko element ni.ShowBalloonTip(30000); – ustawia on czas(w ms) przez jaki nasz dymek będzie wyświetlany. Jeżeli dobrze pamiętam to maksymalny czas, jaki będzie przez system uznawany to 30 sekund. Z moich obserwacji wynika, że czas ten nie jest respektowany przez Windows 10. Nie ważne co tu wpiszemy, 10’tka będzie wyświetlać powiadomienie przez (chyba) z góry ustalony przez Microsoft czas. Jeżeli chodzi jednak o systemy starsze to funkcja ta jak najbardziej działa.

Używanie klasy w praktyce

Okej, skoro wszystko gotowe to weźmy się za użycie naszej klasy(nawet dosyć uniwersalnej) w praktyce. W tym celu w konstruktorze naszego okna wywołajmy:

Dzięki tej linijce po uruchomieniu aplikacji w tray’u pojawi się nasza ikonka 😉

traya

Niby wszystko okej, jednak zamknięcie aplikacji krzyżykiem spowoduje również zamknięcie ikony. Jak temu zaradzić? Najlepiej nie zamykać samego okna tylko je ukryć. W tym celu do konstruktora należy dodać taką oto linijkę:

Oraz powiązaną z tym zdarzeniem metodę:

Po tym zabiegu kliknięcie krzyżyka nie spowoduje zamknięcia aplikacji, a jedynie ukrycie aktywnego okna. Z kolei kliknięcie na ikonę w tray’u przywróci nasze okno do działania. Wszystko działa! 🙂

To może teraz weźmy się za test metody wyświetlającej magiczne „dymki”. W tym celu wewnątrz klasy MainWindow stwórzmy dostępną dla wszystkich zawartych w niej metod zmienną TrayClass trayClass;, dla której tak jak wcześniej w konstruktorze tworzymy nowy obiekt klasy. Kiedy mamy to za sobą, dodajmy do naszego okna jakiś przycisk i… wstawmy w obsługującej zdarzenie kliknięcia metodzie taki oto kod:

To teraz czas na test, kliknijmy na przycisk:

alert

Jak widać na załączonym obrazku, tu również wszystko działa 😉

Na koniec może wkleję cały kod dwóch klas, na których tutaj operowaliśmy:

TrayClass:

MainWindow:

Na koniec można sobie zadać pytanie, czy można to zrobić inaczej? Okazuje się, że tak. Dla zainteresowanych zostawiam linka: klik. Sam nigdy nie korzystałem z tego rozwiązania, jakoś nie miałem potrzeby wyświetlania takich „ładnych” komunikatów. Wystarczały mi standardowe 😉

 

1,607 total views, 1 views today

4 przemyślenia nt. „Aplikacja WPF i ikona w systemowym tray’u

  1. Fajny poradnik, wypróbuję 🙂
    Ale trochę w kodzie bałaganisz, jednak.
    Po pierwsze :
    Co jeśli tray class będę chciał użyć nie w MainWindow ale gdzie indziej? Nie lepiej w metodę wepchać interfejs, który potem będzie implementowany przez dowolny widok w solucji?

    Np.
    public partial class MySampleView: Window, IView

    Wywołanie TrayClass :
    rayClass = new TrayClass(this);

    A w TrayClass :
    private IView _view;
    public TrayClass(IView view)
    {
    _view = view;
    }
    I tu dochodzimy do nazewnictwa. Nie lepiej prywatne pole/propertas nazwać jakoś inaczej i nie używać this. ? Czytelniejsze troszkę.

    Ale to tylko moje luźne spostrzeżenia – ogólnie gut dżob 🙂

    • Ikonę w tray’u tworzy się raczej tylko raz, więc ewentualna przeróbka tej klasy pod inny widok nie byłaby jakimś wielkim problemem. Zmieniamy MainWindow na np. MyWindow i wszystko gra.
      Co do interfejsu masz rację, ładniejsze i bardziej uniwersalne rozwiązanie 😉 Z drugiej strony… zawsze coś takiego i tak trzeba jeszcze dostosować na potrzeby konkretnego projektu.

      Dzięki za miłe słowo! 🙂

Możliwość komentowania jest wyłączona.