get-the-solution

Tray Icon mit WPF

By
on Regards: Article;

Es gibt mir zwei bekannte möglichkeiten ein Tray Icon mit WPF zu realisieren. Die erste ist man erstellt ein WPF Window und erstellt darin, das Tray Icon Objekt. Meiner Meinung nach ist das aber der falsche Weg. Darin wird nur das Tray Icon Objekt gehostet. Die Nachteile:

  • Code ist nicht gut getrennt Tray Icon / Window
  • Will man nur das Tray Icon zum Programmstart anzeigen muss das Fenster versteckt werden

Die zweite, meiner Meinung nach, richtige Lösung wäre, in der App.xaml.cs Datei die Methode OnStartup zu überschreiben und von dort aus das Tray Icon Objekt zu erstellen. Nun kann man beliebig viele Fenster über das Tray Icon erstellen.

Das ganze realisiert man so:

  1. Projekttyp "Neue WPF Anwendung" erstellen
  2. Das vorhandene Window kann man wie man will löschen oder stehen lassen, wenn man dieses später benötigt
  3. In der App.xaml entfernen wir den Eintrag StartupUri="Window1.xaml"
  4. Damit verhindern wir, dass beim Programmstart das Fenster Window1 erstellt und angezeigt wird.
  5. Für das TrayIcon verwenden wir das Objekt NotifyIcon welches sich in der Libary System.Windows.Forms befindet. Wir fügen also zu den Verweisen ->Rechter Mausklick -> Verweis hinzufügen -> System.Windows.Forms und System.Drawing hinzu damit wir auch das Icon setzen können

Ich habe eine kleine Tray Icon Klasse geschrieben, damit man schnell ein paar ContextMenu einträge zum Tray Icon hinzufügen kann. Dazu erstellen wir uns eine neue Klassen-Datei namens Tray.cs und fügen folgenden Code ein.

    using System.Windows.Forms;
    using System;
     
    public class Tray
    {
        private NotifyIcon _notico;
        private bool _Animate = false;
        private ContextMenu _contextMenu = new ContextMenu();
     
        public Tray()
        {
            Initialize();
        }
        public Tray(System.Drawing.Icon pIcon)
        {
            Initialize();
            _notico.Icon = pIcon;
        }
        /// <summary>
        /// Initialisiert das NotifyIcon
        /// </summary>
        private void Initialize()
        {
            // NotifyIcon erzeugen
            _notico = new NotifyIcon();
            _notico.Visible = true;
     
            ContextMenu contextMenu = new ContextMenu();
     
            // Kontextmenüeinträge erzeugen
     
            _notico.ContextMenu = _contextMenu;
     
        }
        public void CreateMenuItem(String pName)
        {
            MenuItem menuItem = new MenuItem();
            menuItem = new MenuItem();
            menuItem.Index = 1;
            menuItem.Name = pName;
            menuItem.Text = "&" + menuItem.Name;
     
            _contextMenu.MenuItems.Add(menuItem);
        }
        public void CreateMenuItem(String pName, bool pTrue)
        {
            MenuItem menuItem = new MenuItem();
            menuItem.Index = 2;
            menuItem.Name = pName;
            menuItem.Text = "&" + menuItem.Name;
            menuItem.Click += (sender, e) =>
            {
                MenuItem m = (MenuItem)sender;
                m.Checked = !m.Checked;
            };
            menuItem.Checked = pTrue;
     
            _contextMenu.MenuItems.Add(menuItem);
        }
        public NotifyIcon NotifyIcon
        {
            get
            {
                return _notico;
            }
        }
    }

Jetzt öffnen wir die App.xaml.cs Datei und überschreiben die Methode OnStartUp().

Damit unser Programm nicht beendet wird, wenn man ein erstelltes Fenster schließt, müssen wir die Propertie ShutdownMode neu setzen.

In der MSDN steht dazu folgendes.

Ruft die Bedingung ab, unter der die Shutdown-Methode aufgerufen wird, oder legt diese fest.

Wir setzen die Propertie deshalb auf den Wert OnExplicitShutdown.

Damit das Tray Icon im Tray überhaupt sichtbar ist, benötigen wir ein Icon. Man kann ein neues Icon direkt im Vs.net erstellen oder ein vorhandenes hinzufügen. Wie man das Icon ins Programm ladet bleibt jedem selber überlassen. Ich lade das Icon einfachhalts halber aus einer Datei.

Danach erstellen wir das Tray Objekt und übergen das Icon welches, wir aus der Datei geladen haben.

Nun können wir, auf die Tray Methoden zugreifen und beliebig viele ContextMenüs erstellen.

Über die Propertie NotifyIcon der Klasse Tray können wir auf die MenüItems zugreifen und deren verhalten bestimmen. Z.b, wenn man auf ein Menüitem Klickt, dass ein neues Fenster erstellt wird, oder dass die komplette Applikation mit samt Tray Icon geschlossen wird.

Das sieht dann so aus:

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data;
    using System.Linq;
    using System.Windows;
    using System.Drawing;
     
    namespace Tray_Icon_WPF
    {
        /// <summary>
        /// Interaction logic for App.xaml
        /// </summary>
        public partial class App : Application
        {
            protected override void OnStartup(StartupEventArgs e)
            {
                this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
     
                //Icon laden
                Icon icon = Icon.ExtractAssociatedIcon(@"C:UsersmartinDocumentsVisual Studio 2008BlogTray Icon WPFTray Icon WPFIcon1.ico"); 
     
                //trayicon erstellen und icon laden
                Tray tray = new Tray(icon);
     
                tray.CreateMenuItem("Fenster aufrufen");
                tray.CreateMenuItem("Beenden");
     
                //Menuitem Fenster aufrufen suchen, zugreifen Click Event anmelden und delegate setzen
                tray.NotifyIcon.ContextMenu.MenuItems.Find("Fenster aufrufen", true).First().Click += (sender, eargs) =>
                {
                    Window1 window = new Window1();
                    window.Show();
     
                };
     
                //Menuitem Beenden suchen, zugreifen Click Event anmelden und delegate setzen
                tray.NotifyIcon.ContextMenu.MenuItems.Find("Beenden", true).First().Click += (sender, eargs) =>
                {
                    //Icon aus tray löschen
                    tray.NotifyIcon.Dispose();
                    Environment.Exit(0);
                };
     
     
                base.OnStartup(e);
            }
        }
    }

Das Demo Projekt ist hier. Wenn ihr die Demo ausführt, müsst ihr den Pfad zum Icon anpassen. Über Fragen, Anregungen, Kritik freu ich mich.

Links: Guter Artikel über das Tray Icon, allerdings wird der ShutdownMode nicht erwähnt http://www.codecomplete.de/blogs/xamlblog/archive/2008/12/15/wpfanwendung-mit-trayicon.aspx So sollte es meiner Meinung nicht machen (Code im Window) http://possemeeg.wordpress.com/2007/09/06/minimize-to-tray-icon-in-wpf/