Notifyicon

Verwenden von TrayIcon´s ohne Referenz auf System.Windows.Forms

Hallo,

In meinem Zivildienstprojekt “LWD.NET” will ich vermeiden eine Referenz auf die Windows Forms Bibliothek zu vermeiden, da WPF-Mäßig keine Unterstützung für ein Tray-Icon (die Icons neben der System-Uhr) mitliefer habe ich mich ein wenig mit der WinAPI herumgeschlagen und eine kleine Klasse geschrieben die mir die Arbeit abnimmt.

Vorgehensweiße:

- Dem Konstruktor werden, WPF-Window, ein System.Drawing.Icon und der String für den Namen übergeben

- Dieser erzeugt die benötigte “NOTIFYICONDATA” Struktur, abonniert die Events Closing und StateChanged vom Window selber sowie mithilfe von “HwndSource” alle Windows-Messages die das Fenster erhält.

- Wird das Fenster nun minimiert, speichert sich die Klasse den vorherigen Status (Maximiert oder Resizeable), versteckt das Fenster (über Hide()) und setzt sich selber als Icon in den Traybereich

- Wird auf das Tray-Icon geklickt erhält das WPF-Window eine Windows-Message mit der ID “WM_MyMessage” (Achtung! Dadurch kann diese Klasse nicht mehrmals verwendet werden! Müsste eindeutig für jedes TrayIcon sein ODER die uID NOTIFYICONDATA) und das Tray-Icon wird entfernt sowie das Fenster wieder wiederhergestellt.

[codesyntax lang="csharp"]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Runtime.InteropServices;
using System.Windows.Interop;

namespace LWD.NET
{
    public class TrayIcon
    {
        IntPtr m_Handle;
        Window m_Window;
        WindowState m_storedWindowState;
        NOTIFYICONDATA m_Data;
        System.Drawing.Icon m_Icon;

        const int TRAY_ADD = 0x00000000;
        const int TRAY_MODIFY = 0x00000001;
        const int TRAY_DELETE = 0x00000002;

        const int WM_MyMessage = 0x400;

        [DllImport("shell32.dll")]
        static extern bool Shell_NotifyIcon(uint dwMessage,[In] ref NOTIFYICONDATA pnid);
        struct NOTIFYICONDATA
        {
            /// <summary>
            /// Size of this structure, in bytes.
            /// </summary>
            public int cbSize;

            /// <summary>
            /// Handle to the window that receives notification messages associated with an icon in the
            /// taskbar status area. The Shell uses hWnd and uID to identify which icon to operate on
            /// when Shell_NotifyIcon is invoked.
            /// </summary>
            public IntPtr hwnd;

            /// <summary>
            /// Application-defined identifier of the taskbar icon. The Shell uses hWnd and uID to identify
            /// which icon to operate on when Shell_NotifyIcon is invoked. You can have multiple icons
            /// associated with a single hWnd by assigning each a different uID.
            /// </summary>
            public int uID;

            /// <summary>
            /// Flags that indicate which of the other members contain valid data. This member can be
            /// a combination of the NIF_XXX constants.
            /// </summary>
            public int uFlags;

            /// <summary>
            /// Application-defined message identifier. The system uses this identifier to send
            /// notifications to the window identified in hWnd.
            /// </summary>
            public int uCallbackMessage;

            /// <summary>
            /// Handle to the icon to be added, modified, or deleted.
            /// </summary>
            public IntPtr hIcon;

            /// <summary>
            /// String with the text for a standard ToolTip. It can have a maximum of 64 characters including
            /// the terminating NULL. For Version 5.0 and later, szTip can have a maximum of
            /// 128 characters, including the terminating NULL.
            /// </summary>
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string szTip;

            /// <summary>
            /// State of the icon.
            /// </summary>
            public int dwState;

            /// <summary>
            /// A value that specifies which bits of the state member are retrieved or modified.
            /// For example, setting this member to NIS_HIDDEN causes only the item's hidden state to be retrieved.
            /// </summary>
            public int dwStateMask;

            /// <summary>
            /// String with the text for a balloon ToolTip. It can have a maximum of 255 characters.
            /// To remove the ToolTip, set the NIF_INFO flag in uFlags and set szInfo to an empty string.
            /// </summary>
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string szInfo;

            /// <summary>
            /// NOTE: This field is also used for the Timeout value. Specifies whether the Shell notify
            /// icon interface should use Windows 95 or Windows 2000
            /// behavior. For more information on the differences in these two behaviors, see
            /// Shell_NotifyIcon. This member is only employed when using Shell_NotifyIcon to send an
            /// NIM_VERSION message.
            /// </summary>
            public int uVersion;

            /// <summary>
            /// String containing a title for a balloon ToolTip. This title appears in boldface
            /// above the text. It can have a maximum of 63 characters.
            /// </summary>
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string szInfoTitle;

            /// <summary>
            /// Adds an icon to a balloon ToolTip. It is placed to the left of the title. If the
            /// szTitleInfo member is zero-length, the icon is not shown. See
            /// <see cref="BalloonIconStyle">RMUtils.WinAPI.Structs.BalloonIconStyle</see> for more
            /// information.
            /// </summary>
            public int dwInfoFlags;
        }

        public TrayIcon(Window win, System.Drawing.Icon Icon,string Tip)
        {
            m_Window = win;
            m_Icon = Icon;
            m_Handle = new WindowInteropHelper(m_Window).Handle;

            HwndSource source = PresentationSource.FromVisual(m_Window) as HwndSource;
            source.AddHook(WndProc);

            m_Window.Closing += new System.ComponentModel.CancelEventHandler(win_Closing);
            m_Window.StateChanged += new EventHandler(win_StateChanged);

            m_Data = new NOTIFYICONDATA();

            if (Environment.OSVersion.Version.Major >= 6)
            {
                m_Data.cbSize = Marshal.SizeOf(m_Data);
            }
            else
            {
                m_Data.cbSize = 504;
                m_Data.uVersion = 10;
            }
            m_Data.uFlags = 0x01 | 0x02 | 0x04;

            m_Data.hwnd = m_Handle;
            m_Data.uCallbackMessage = WM_MyMessage;
            m_Data.hIcon = Icon.Handle;
            m_Data.uID = 0x0;
            m_Data.szTip = Tip;
        }

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if ((int)msg == WM_MyMessage)
            {
                if ((int)lParam == 0x201)
                {
                    //Click ?
                    m_Window.Show();
                    m_Window.WindowState = m_storedWindowState;
                }
            }
            return IntPtr.Zero;
        }

        public void ShowTrayIcon()
        {
            Shell_NotifyIcon(TRAY_ADD, ref m_Data);
        }

        public void HideTrayIcon()
        {
            Shell_NotifyIcon(TRAY_DELETE, ref m_Data);
        }

        void win_StateChanged(object sender, EventArgs e)
        {
            if (m_Window.WindowState == WindowState.Minimized)
            {
                m_Window.Hide();
                ShowTrayIcon();
            }
            else
            {
                m_storedWindowState = m_Window.WindowState;
                HideTrayIcon();
            }            
        }

        void win_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            HideTrayIcon();
        }

        void m_notifyIcon_Click(object sender, EventArgs e)
        {
            m_Window.Show();
            m_Window.WindowState = m_storedWindowState;
        }
    }
}

[/codesyntax]