WPF實(shí)現(xiàn)基礎(chǔ)控件之托盤的示例代碼
WPF 基礎(chǔ)控件之托盤
框架使用大于等于.NET40
。
Visual Studio 2022
。
項(xiàng)目使用 MIT 開源許可協(xié)議。
新建NotifyIcon
自定義控件繼承自FrameworkElement
。
創(chuàng)建托盤程序主要借助與 Win32API:
- 注冊(cè)窗體對(duì)象
RegisterClassEx
。 - 注冊(cè)消息獲取對(duì)應(yīng)消息標(biāo)識(shí)
Id
RegisterWindowMessage
。 - 創(chuàng)建窗體(本質(zhì)上托盤在創(chuàng)建時(shí)需要一個(gè)窗口句柄,完全可以將主窗體的句柄給進(jìn)去,但是為了更好的管理消息以及托盤的生命周期,通常會(huì)創(chuàng)建一個(gè)獨(dú)立不可見的窗口)
CreateWindowEx
。
以下2點(diǎn)需要注意:
- 托盤控件的
ContextMenu
菜單MenuItem
在使用binding
時(shí)無效,是因?yàn)?code>DataContext沒有帶過去,需要重新賦值一次。 - 托盤控件發(fā)送
ShowBalloonTip
消息通知時(shí)候需新建Shell_NotifyIcon
。 - Nuget 最新
Install-Package WPFDevelopers
1.0.9.1-preview
示例代碼
1) NotifyIcon.cs 代碼如下:
using?System; using?System.IO; using?System.Runtime.InteropServices; using?System.Threading; using?System.Windows; using?System.Windows.Controls; using?System.Windows.Controls.Primitives; using?System.Windows.Data; using?System.Windows.Input; using?System.Windows.Media; using?System.Windows.Media.Imaging; using?WPFDevelopers.Controls.Runtimes; using?WPFDevelopers.Controls.Runtimes.Interop; using?WPFDevelopers.Controls.Runtimes.Shell32; using?WPFDevelopers.Controls.Runtimes.User32; namespace?WPFDevelopers.Controls { ????public?class?NotifyIcon?:?FrameworkElement,?IDisposable ????{ ????????private?static?NotifyIcon?NotifyIconCache; ????????public?static?readonly?DependencyProperty?ContextContentProperty?=?DependencyProperty.Register( ????????????"ContextContent",?typeof(object),?typeof(NotifyIcon),?new?PropertyMetadata(default)); ????????public?static?readonly?DependencyProperty?IconProperty?= ????????????DependencyProperty.Register("Icon",?typeof(ImageSource),?typeof(NotifyIcon), ????????????????new?PropertyMetadata(default,?OnIconPropertyChanged)); ????????public?static?readonly?DependencyProperty?TitleProperty?= ????????????DependencyProperty.Register("Title",?typeof(string),?typeof(NotifyIcon), ????????????????new?PropertyMetadata(default,?OnTitlePropertyChanged)); ????????public?static?readonly?RoutedEvent?ClickEvent?= ????????????EventManager.RegisterRoutedEvent("Click",?RoutingStrategy.Bubble, ????????????????typeof(RoutedEventHandler),?typeof(NotifyIcon)); ????????public?static?readonly?RoutedEvent?MouseDoubleClickEvent?= ????????????EventManager.RegisterRoutedEvent("MouseDoubleClick",?RoutingStrategy.Bubble, ????????????????typeof(RoutedEventHandler),?typeof(NotifyIcon)); ????????private?static?bool?s_Loaded?=?false; ????????private?static?NotifyIcon?s_NotifyIcon; ????????//這是窗口名稱 ????????private?readonly?string?_TrayWndClassName; ????????//這個(gè)是窗口消息名稱 ????????private?readonly?string?_TrayWndMessage; ????????//這個(gè)是窗口消息回調(diào)(窗口消息都需要在此捕獲) ????????private?readonly?WndProc?_TrayWndProc; ????????private?Popup?_contextContent; ????????private?bool?_doubleClick; ????????//圖標(biāo)句柄 ????????private?IntPtr?_hIcon?=?IntPtr.Zero; ????????private?ImageSource?_icon; ????????private?IntPtr?_iconHandle; ????????private?int?_IsShowIn; ????????//托盤對(duì)象 ????????private?NOTIFYICONDATA?_NOTIFYICONDATA; ????????//這個(gè)是傳遞給托盤的鼠標(biāo)消息id ????????private?int?_TrayMouseMessage; ????????//窗口句柄 ????????private?IntPtr?_TrayWindowHandle?=?IntPtr.Zero; ????????//通過注冊(cè)窗口消息可以獲取唯一標(biāo)識(shí)Id ????????private?int?_WmTrayWindowMessage; ????????private?bool?disposedValue; ????????public?NotifyIcon() ????????{ ????????????_TrayWndClassName?=?$"WPFDevelopers_{Guid.NewGuid()}"; ????????????_TrayWndProc?=?WndProc_CallBack; ????????????_TrayWndMessage?=?"TrayWndMessageName"; ????????????_TrayMouseMessage?=?(int)WM.USER?+?1024; ????????????Start(); ????????????if?(Application.Current?!=?null) ????????????{ ????????????????//Application.Current.MainWindow.Closed?+=?(s,?e)?=>?Dispose(); ????????????????Application.Current.Exit?+=?(s,?e)?=>?Dispose(); ????????????} ????????????NotifyIconCache?=?this; ????????} ????????static?NotifyIcon() ????????{ ????????????DataContextProperty.OverrideMetadata(typeof(NotifyIcon),?new?FrameworkPropertyMetadata(DataContextPropertyChanged)); ????????????ContextMenuProperty.OverrideMetadata(typeof(NotifyIcon),?new?FrameworkPropertyMetadata(ContextMenuPropertyChanged)); ????????} ????????private?static?void?DataContextPropertyChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e)?=> ????????????((NotifyIcon)d).OnDataContextPropertyChanged(e); ????????private?void?OnDataContextPropertyChanged(DependencyPropertyChangedEventArgs?e) ????????{ ????????????UpdateDataContext(_contextContent,?e.OldValue,?e.NewValue); ????????????UpdateDataContext(ContextMenu,?e.OldValue,?e.NewValue); ????????} ????????private?void?UpdateDataContext(FrameworkElement?target,?object?oldValue,?object?newValue) ????????{ ????????????if?(target?==?null?||?BindingOperations.GetBindingExpression(target,?DataContextProperty)?!=?null)?return; ????????????if?(ReferenceEquals(this,?target.DataContext)?||?Equals(oldValue,?target.DataContext)) ????????????{ ????????????????target.DataContext?=?newValue????this; ????????????} ????????} ????????private?static?void?ContextMenuPropertyChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????var?ctl?=?(NotifyIcon)d; ????????????ctl.OnContextMenuPropertyChanged(e); ????????} ????????private?void?OnContextMenuPropertyChanged(DependencyPropertyChangedEventArgs?e)?=> ????????????UpdateDataContext((ContextMenu)e.NewValue,?null,?DataContext); ????????public?object?ContextContent ????????{ ????????????get?=>?GetValue(ContextContentProperty); ????????????set?=>?SetValue(ContextContentProperty,?value); ????????} ????????public?ImageSource?Icon ????????{ ????????????get?=>?(ImageSource)GetValue(IconProperty); ????????????set?=>?SetValue(IconProperty,?value); ????????} ????????public?string?Title ????????{ ????????????get?=>?(string)GetValue(TitleProperty); ????????????set?=>?SetValue(TitleProperty,?value); ????????} ????????public?void?Dispose() ????????{ ????????????Dispose(true); ????????????GC.SuppressFinalize(this); ????????} ????????private?static?void?OnTitlePropertyChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????if?(d?is?NotifyIcon?trayService) ????????????????trayService.ChangeTitle(e.NewValue?.ToString()); ????????} ????????private?static?void?OnIconPropertyChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e) ????????{ ????????????if?(d?is?NotifyIcon?trayService) ????????????{ ????????????????var?notifyIcon?=?(NotifyIcon)d; ????????????????notifyIcon._icon?=?(ImageSource)e.NewValue; ????????????????trayService.ChangeIcon(); ????????????} ????????} ????????public?event?RoutedEventHandler?Click ????????{ ????????????add?=>?AddHandler(ClickEvent,?value); ????????????remove?=>?RemoveHandler(ClickEvent,?value); ????????} ????????public?event?RoutedEventHandler?MouseDoubleClick ????????{ ????????????add?=>?AddHandler(MouseDoubleClickEvent,?value); ????????????remove?=>?RemoveHandler(MouseDoubleClickEvent,?value); ????????} ????????private?static?void?Current_Exit(object?sender,?ExitEventArgs?e) ????????{ ????????????s_NotifyIcon?.Dispose(); ????????????s_NotifyIcon?=?default; ????????} ????????public?bool?Start() ????????{ ????????????RegisterClass(_TrayWndClassName,?_TrayWndProc,?_TrayWndMessage); ????????????LoadNotifyIconData(string.Empty); ????????????Show(); ????????????return?true; ????????} ????????public?bool?Stop() ????????{ ????????????//銷毀窗體 ????????????if?(_TrayWindowHandle?!=?IntPtr.Zero) ????????????????if?(User32Interop.IsWindow(_TrayWindowHandle)) ????????????????????User32Interop.DestroyWindow(_TrayWindowHandle); ????????????//反注冊(cè)窗口類 ????????????if?(!string.IsNullOrWhiteSpace(_TrayWndClassName)) ????????????????User32Interop.UnregisterClassName(_TrayWndClassName,?Kernel32Interop.GetModuleHandle(default)); ????????????//銷毀Icon ????????????if?(_hIcon?!=?IntPtr.Zero) ????????????????User32Interop.DestroyIcon(_hIcon); ????????????Hide(); ????????????return?true; ????????} ????????///?<summary> ????????///?????注冊(cè)并創(chuàng)建窗口對(duì)象 ????????///?</summary> ????????///?<param?name="className">窗口名稱</param> ????????///?<param?name="messageName">窗口消息名稱</param> ????????///?<returns></returns> ????????private?bool?RegisterClass(string?className,?WndProc?wndproccallback,?string?messageName) ????????{ ????????????var?wndClass?=?new?WNDCLASSEX ????????????{ ????????????????cbSize?=?Marshal.SizeOf(typeof(WNDCLASSEX)), ????????????????style?=?0, ????????????????lpfnWndProc?=?wndproccallback, ????????????????cbClsExtra?=?0, ????????????????cbWndExtra?=?0, ????????????????hInstance?=?IntPtr.Zero, ????????????????hCursor?=?IntPtr.Zero, ????????????????hbrBackground?=?IntPtr.Zero, ????????????????lpszMenuName?=?string.Empty, ????????????????lpszClassName?=?className ????????????}; ????????????//注冊(cè)窗體對(duì)象 ????????????User32Interop.RegisterClassEx(ref?wndClass); ????????????//注冊(cè)消息獲取對(duì)應(yīng)消息標(biāo)識(shí)id ????????????_WmTrayWindowMessage?=?User32Interop.RegisterWindowMessage(messageName); ????????????//創(chuàng)建窗體(本質(zhì)上托盤在創(chuàng)建時(shí)需要一個(gè)窗口句柄,完全可以將主窗體的句柄給進(jìn)去,但是為了更好的管理消息以及托盤的生命周期,通常會(huì)創(chuàng)建一個(gè)獨(dú)立不可見的窗口) ????????????_TrayWindowHandle?=?User32Interop.CreateWindowEx(0,?className,?"",?0,?0,?0,?1,?1,?IntPtr.Zero,?IntPtr.Zero, ????????????????IntPtr.Zero,?IntPtr.Zero); ????????????return?true; ????????} ????????///?<summary> ????????///?????創(chuàng)建托盤對(duì)象 ????????///?</summary> ????????///?<param?name="icon">圖標(biāo)路徑,可以修改托盤圖標(biāo)(本質(zhì)上是可以接受用戶傳入一個(gè)圖片對(duì)象,然后將圖片轉(zhuǎn)成Icon,但是算了這個(gè)有點(diǎn)復(fù)雜)</param> ????????///?<param?name="title">托盤的tooltip</param> ????????///?<returns></returns> ????????private?bool?LoadNotifyIconData(string?title) ????????{ ????????????lock?(this) ????????????{ ????????????????_NOTIFYICONDATA?=?NOTIFYICONDATA.GetDefaultNotifyData(_TrayWindowHandle); ????????????????if?(_TrayMouseMessage?!=?0) ????????????????????_NOTIFYICONDATA.uCallbackMessage?=?(uint)_TrayMouseMessage; ????????????????else ????????????????????_TrayMouseMessage?=?(int)_NOTIFYICONDATA.uCallbackMessage; ????????????????if?(_iconHandle?==?IntPtr.Zero) ????????????????{ ????????????????????var?processPath?=?Kernel32Interop.GetModuleFileName(new?HandleRef()); ????????????????????if?(!string.IsNullOrWhiteSpace(processPath)) ????????????????????{ ????????????????????????var?index?=?IntPtr.Zero; ????????????????????????var?hIcon?=?Shell32Interop.ExtractAssociatedIcon(IntPtr.Zero,?processPath,?ref?index); ????????????????????????_NOTIFYICONDATA.hIcon?=?hIcon; ????????????????????????_hIcon?=?hIcon; ????????????????????} ????????????????} ????????????????if?(!string.IsNullOrWhiteSpace(title)) ????????????????????_NOTIFYICONDATA.szTip?=?title; ????????????} ????????????return?true; ????????} ????????private?bool?Show() ????????{ ????????????var?command?=?NotifyCommand.NIM_Add; ????????????if?(Thread.VolatileRead(ref?_IsShowIn)?==?1) ????????????????command?=?NotifyCommand.NIM_Modify; ????????????else ????????????????Thread.VolatileWrite(ref?_IsShowIn,?1); ????????????lock?(this) ????????????{ ????????????????return?Shell32Interop.Shell_NotifyIcon(command,?ref?_NOTIFYICONDATA); ????????????} ????????} ????????internal?static?int?AlignToBytes(double?original,?int?nBytesCount) ????????{ ????????????var?nBitsCount?=?8?<<?(nBytesCount?-?1); ????????????return?((int)Math.Ceiling(original)?+?(nBitsCount?-?1))?/?nBitsCount?*?nBitsCount; ????????} ????????private?static?byte[]?GenerateMaskArray(int?width,?int?height,?byte[]?colorArray) ????????{ ????????????var?nCount?=?width?*?height; ????????????var?bytesPerScanLine?=?AlignToBytes(width,?2)?/?8; ????????????var?bitsMask?=?new?byte[bytesPerScanLine?*?height]; ????????????for?(var?i?=?0;?i?<?nCount;?i++) ????????????{ ????????????????var?hPos?=?i?%?width; ????????????????var?vPos?=?i?/?width; ????????????????var?byteIndex?=?hPos?/?8; ????????????????var?offsetBit?=?(byte)(0x80?>>?(hPos?%?8)); ????????????????if?(colorArray[i?*?4?+?3]?==?0x00) ????????????????????bitsMask[byteIndex?+?bytesPerScanLine?*?vPos]?|=?offsetBit; ????????????????else ????????????????????bitsMask[byteIndex?+?bytesPerScanLine?*?vPos]?&=?(byte)~offsetBit; ????????????????if?(hPos?==?width?-?1?&&?width?==?8)?bitsMask[1?+?bytesPerScanLine?*?vPos]?=?0xff; ????????????} ????????????return?bitsMask; ????????} ????????private?byte[]?BitmapImageToByteArray(BitmapImage?bmp) ????????{ ????????????byte[]?bytearray?=?null; ????????????try ????????????{ ????????????????var?smarket?=?bmp.StreamSource; ????????????????if?(smarket?!=?null?&&?smarket.Length?>?0) ????????????????{ ????????????????????//設(shè)置當(dāng)前位置 ????????????????????smarket.Position?=?0; ????????????????????using?(var?br?=?new?BinaryReader(smarket)) ????????????????????{ ????????????????????????bytearray?=?br.ReadBytes((int)smarket.Length); ????????????????????} ????????????????} ????????????} ????????????catch?(Exception?ex) ????????????{ ????????????} ????????????return?bytearray; ????????} ????????private?byte[]?ConvertBitmapSourceToBitmapImage( ????????????BitmapSource?bitmapSource) ????????{ ????????????byte[]?imgByte?=?default; ????????????if?(!(bitmapSource?is?BitmapImage?bitmapImage)) ????????????{ ????????????????bitmapImage?=?new?BitmapImage(); ????????????????var?encoder?=?new?BmpBitmapEncoder(); ????????????????encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); ????????????????using?(var?memoryStream?=?new?MemoryStream()) ????????????????{ ????????????????????encoder.Save(memoryStream); ????????????????????memoryStream.Position?=?0; ????????????????????bitmapImage.BeginInit(); ????????????????????bitmapImage.CacheOption?=?BitmapCacheOption.OnLoad; ????????????????????bitmapImage.StreamSource?=?memoryStream; ????????????????????bitmapImage.EndInit(); ????????????????????imgByte?=?BitmapImageToByteArray(bitmapImage); ????????????????} ????????????} ????????????return?imgByte; ????????} ????????internal?static?IconHandle?CreateIconCursor(byte[]?xor,?int?width,?int?height,?int?xHotspot, ????????????int?yHotspot,?bool?isIcon) ????????{ ????????????var?bits?=?IntPtr.Zero; ????????????BitmapHandle?colorBitmap?=?null; ????????????var?bi?=?new?BITMAPINFO(width,?-height,?32) ????????????{ ????????????????bmiHeader_biCompression?=?0 ????????????}; ????????????colorBitmap?=?Gdi32Interop.CreateDIBSection(new?HandleRef(null,?IntPtr.Zero),?ref?bi,?0,?ref?bits,?null,?0); ????????????if?(colorBitmap.IsInvalid?||?bits?==?IntPtr.Zero)?return?IconHandle.GetInvalidIcon(); ????????????Marshal.Copy(xor,?0,?bits,?xor.Length); ????????????var?maskArray?=?GenerateMaskArray(width,?height,?xor); ????????????var?maskBitmap?=?Gdi32Interop.CreateBitmap(width,?height,?1,?1,?maskArray); ????????????if?(maskBitmap.IsInvalid)?return?IconHandle.GetInvalidIcon(); ????????????var?iconInfo?=?new?Gdi32Interop.ICONINFO ????????????{ ????????????????fIcon?=?isIcon, ????????????????xHotspot?=?xHotspot, ????????????????yHotspot?=?yHotspot, ????????????????hbmMask?=?maskBitmap, ????????????????hbmColor?=?colorBitmap ????????????}; ????????????return?User32Interop.CreateIconIndirect(iconInfo); ????????} ????????private?bool?ChangeIcon() ????????{ ????????????var?bitmapFrame?=?_icon?as?BitmapFrame; ????????????if?(bitmapFrame?!=?null?&&?bitmapFrame.Decoder?!=?null) ????????????????if?(bitmapFrame.Decoder?is?IconBitmapDecoder) ????????????????{ ????????????????????//var?iconBitmapDecoder?=?new?Rect(0,?0,?_icon.Width,?_icon.Height); ????????????????????//var?dv?=?new?DrawingVisual(); ????????????????????//var?dc?=?dv.RenderOpen(); ????????????????????//dc.DrawImage(_icon,?iconBitmapDecoder); ????????????????????//dc.Close(); ????????????????????//var?bmp?=?new?RenderTargetBitmap((int)_icon.Width,?(int)_icon.Height,?96,?96, ????????????????????//????PixelFormats.Pbgra32); ????????????????????//bmp.Render(dv); ????????????????????//BitmapSource?bitmapSource?=?bmp; ????????????????????//if?(bitmapSource.Format?!=?PixelFormats.Bgra32?&&?bitmapSource.Format?!=?PixelFormats.Pbgra32) ????????????????????//????bitmapSource?=?new?FormatConvertedBitmap(bitmapSource,?PixelFormats.Bgra32,?null,?0.0); ????????????????????var?w?=?bitmapFrame.PixelWidth; ????????????????????var?h?=?bitmapFrame.PixelHeight; ????????????????????var?bpp?=?bitmapFrame.Format.BitsPerPixel; ????????????????????var?stride?=?(bpp?*?w?+?31)?/?32?*?4; ????????????????????var?sizeCopyPixels?=?stride?*?h; ????????????????????var?xor?=?new?byte[sizeCopyPixels]; ????????????????????bitmapFrame.CopyPixels(xor,?stride,?0); ????????????????????var?iconHandle?=?CreateIconCursor(xor,?w,?h,?0,?0,?true); ????????????????????_iconHandle?=?iconHandle.CriticalGetHandle(); ????????????????} ????????????if?(Thread.VolatileRead(ref?_IsShowIn)?!=?1) ????????????????return?false; ????????????if?(_hIcon?!=?IntPtr.Zero) ????????????{ ????????????????User32Interop.DestroyIcon(_hIcon); ????????????????_hIcon?=?IntPtr.Zero; ????????????} ????????????lock?(this) ????????????{ ????????????????if?(_iconHandle?!=?IntPtr.Zero) ????????????????{ ????????????????????var?hIcon?=?_iconHandle; ????????????????????_NOTIFYICONDATA.hIcon?=?hIcon; ????????????????????_hIcon?=?hIcon; ????????????????} ????????????????else ????????????????{ ????????????????????_NOTIFYICONDATA.hIcon?=?IntPtr.Zero; ????????????????} ????????????????return?Shell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Modify,?ref?_NOTIFYICONDATA); ????????????} ????????} ????????private?bool?ChangeTitle(string?title) ????????{ ????????????if?(Thread.VolatileRead(ref?_IsShowIn)?!=?1) ????????????????return?false; ????????????lock?(this) ????????????{ ????????????????_NOTIFYICONDATA.szTip?=?title; ????????????????return?Shell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Modify,?ref?_NOTIFYICONDATA); ????????????} ????????} ????????public?static?void?ShowBalloonTip(string?title,?string?content,?NotifyIconInfoType?infoType) ????????{ ????????????if?(NotifyIconCache?!=?null) ????????????????NotifyIconCache.ShowBalloonTips(title,?content,?infoType); ????????} ????????public?void?ShowBalloonTips(string?title,?string?content,?NotifyIconInfoType?infoType) ????????{ ????????????if?(Thread.VolatileRead(ref?_IsShowIn)?!=?1) ????????????????return; ????????????var?_ShowNOTIFYICONDATA?=?NOTIFYICONDATA.GetDefaultNotifyData(_TrayWindowHandle); ????????????_ShowNOTIFYICONDATA.uFlags?=?NIFFlags.NIF_INFO; ????????????_ShowNOTIFYICONDATA.szInfoTitle?=?title????string.Empty; ????????????_ShowNOTIFYICONDATA.szInfo?=?content????string.Empty; ????????????switch?(infoType) ????????????{ ????????????????case?NotifyIconInfoType.Info: ????????????????????_ShowNOTIFYICONDATA.dwInfoFlags?=?NIIFFlags.NIIF_INFO; ????????????????????break; ????????????????case?NotifyIconInfoType.Warning: ????????????????????_ShowNOTIFYICONDATA.dwInfoFlags?=?NIIFFlags.NIIF_WARNING; ????????????????????break; ????????????????case?NotifyIconInfoType.Error: ????????????????????_ShowNOTIFYICONDATA.dwInfoFlags?=?NIIFFlags.NIIF_ERROR; ????????????????????break; ????????????????case?NotifyIconInfoType.None: ????????????????????_ShowNOTIFYICONDATA.dwInfoFlags?=?NIIFFlags.NIIF_NONE; ????????????????????break; ????????????} ????????????Shell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Modify,?ref?_ShowNOTIFYICONDATA); ????????} ????????private?bool?Hide() ????????{ ????????????var?isShow?=?Thread.VolatileRead(ref?_IsShowIn); ????????????if?(isShow?!=?1) ????????????????return?true; ????????????Thread.VolatileWrite(ref?_IsShowIn,?0); ????????????lock?(this) ????????????{ ????????????????return?Shell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Delete,?ref?_NOTIFYICONDATA); ????????????} ????????} ????????private?IntPtr?WndProc_CallBack(IntPtr?hwnd,?WM?msg,?IntPtr?wParam,?IntPtr?lParam) ????????{ ????????????//這是窗口相關(guān)的消息 ????????????if?((int)msg?==?_WmTrayWindowMessage) ????????????{ ????????????} ????????????else?if?((int)msg?==?_TrayMouseMessage)?//這是托盤上鼠標(biāo)相關(guān)的消息 ????????????{ ????????????????switch?((WM)(long)lParam) ????????????????{ ????????????????????case?WM.LBUTTONDOWN: ????????????????????????break; ????????????????????case?WM.LBUTTONUP: ????????????????????????WMMouseUp(MouseButton.Left); ????????????????????????break; ????????????????????case?WM.LBUTTONDBLCLK: ????????????????????????WMMouseDown(MouseButton.Left,?2); ????????????????????????break; ????????????????????case?WM.RBUTTONDOWN: ????????????????????????break; ????????????????????case?WM.RBUTTONUP: ????????????????????????OpenMenu(); ????????????????????????break; ????????????????????case?WM.MOUSEMOVE: ????????????????????????break; ????????????????????case?WM.MOUSEWHEEL: ????????????????????????break; ????????????????} ????????????} ????????????else?if?(msg?==?WM.COMMAND) ????????????{ ????????????} ????????????return?User32Interop.DefWindowProc(hwnd,?msg,?wParam,?lParam); ????????} ????????private?void?WMMouseUp(MouseButton?button) ????????{ ????????????if?(!_doubleClick?&&?button?==?MouseButton.Left) ????????????????RaiseEvent(new?MouseButtonEventArgs( ????????????????????Mouse.PrimaryDevice, ????????????????????Environment.TickCount,?button) ????????????????{ ????????????????????RoutedEvent?=?ClickEvent ????????????????}); ????????????_doubleClick?=?false; ????????} ????????private?void?WMMouseDown(MouseButton?button,?int?clicks) ????????{ ????????????if?(clicks?==?2) ????????????{ ????????????????RaiseEvent(new?MouseButtonEventArgs( ????????????????????Mouse.PrimaryDevice, ????????????????????Environment.TickCount,?button) ????????????????{ ????????????????????RoutedEvent?=?MouseDoubleClickEvent ????????????????}); ????????????????_doubleClick?=?true; ????????????} ????????} ????????private?void?OpenMenu() ????????{ ????????????if?(ContextContent?!=?null) ????????????{ ????????????????_contextContent?=?new?Popup ????????????????{ ????????????????????Placement?=?PlacementMode.Mouse, ????????????????????AllowsTransparency?=?true, ????????????????????StaysOpen?=?false, ????????????????????UseLayoutRounding?=?true, ????????????????????SnapsToDevicePixels?=?true ????????????????}; ????????????????_contextContent.Child?=?new?ContentControl ????????????????{ ????????????????????Content?=?ContextContent ????????????????}; ????????????????UpdateDataContext(_contextContent,?null,?DataContext); ????????????????_contextContent.IsOpen?=?true; ????????????????User32Interop.SetForegroundWindow(_contextContent.Child.GetHandle()); ????????????} ????????????else?if?(ContextMenu?!=?null) ????????????{ ????????????????if?(ContextMenu.Items.Count?==?0)?return; ????????????????ContextMenu.InvalidateProperty(StyleProperty); ????????????????foreach?(var?item?in?ContextMenu.Items) ????????????????????if?(item?is?MenuItem?menuItem) ????????????????????{ ????????????????????????menuItem.InvalidateProperty(StyleProperty); ????????????????????} ????????????????????else ????????????????????{ ????????????????????????var?container?=?ContextMenu.ItemContainerGenerator.ContainerFromItem(item)?as?MenuItem; ????????????????????????container?.InvalidateProperty(StyleProperty); ????????????????????} ????????????????ContextMenu.Placement?=?PlacementMode.Mouse; ????????????????ContextMenu.IsOpen?=?true; ????????????????User32Interop.SetForegroundWindow(ContextMenu.GetHandle()); ????????????} ????????} ????????protected?virtual?void?Dispose(bool?disposing) ????????{ ????????????if?(!disposedValue) ????????????{ ????????????????if?(disposing) ????????????????????Stop(); ????????????????disposedValue?=?true; ????????????} ????????} ????} ????public?enum?NotifyIconInfoType ????{ ????????///?<summary> ????????///?????No?Icon. ????????///?</summary> ????????None, ????????///?<summary> ????????///?????A?Information?Icon. ????????///?</summary> ????????Info, ????????///?<summary> ????????///?????A?Warning?Icon. ????????///?</summary> ????????Warning, ????????///?<summary> ????????///?????A?Error?Icon. ????????///?</summary> ????????Error ????} }
2) NotifyIconExample.xaml 代碼如下:
ContextMenu
使用如下:
<wpfdev:NotifyIcon?Title="WPF開發(fā)者"> ????????????<wpfdev:NotifyIcon.ContextMenu> ????????????????<ContextMenu> ????????????????????<MenuItem?Header="托盤消息"?Click="SendMessage_Click"/> ????????????????????<MenuItem?Header="退出"?Click="Quit_Click"/> ????????????????</ContextMenu> ????????????</wpfdev:NotifyIcon.ContextMenu> ????????</wpfdev:NotifyIcon>
ContextContent
使用如下:
<wpfdev:NotifyIcon?Title="WPF開發(fā)者"> ????<wpfdev:NotifyIcon.ContextContent> ??????????<Border?CornerRadius="3"?Margin="10"? ??????????????????Background="{DynamicResource?BackgroundSolidColorBrush}"? ??????????Effect="{StaticResource?NormalShadowDepth}"> ??????????<StackPanel?VerticalAlignment="Center"?Margin="16"> ????????????<Rectangle?Width="100"?Height="100"> ??????????????<Rectangle.Fill> ??????????????????<ImageBrush?ImageSource="pack://application:,,,/Logo.ico"/> ??????????????</Rectangle.Fill> ????????????</Rectangle> ????????????????<StackPanel?Margin="0,16,0,0"?HorizontalAlignment="Center"?Orientation="Horizontal"> ??????????????????<Button?MinWidth="100"?Content="關(guān)于"? ??????????????????????????Style="{DynamicResource?PrimaryButton}"? ??????????????????????????Command="{Binding?GithubCommand}"?/> ??????????????????<Button?Margin="16,0,0,0"?MinWidth="100"?Content="退出"?Click="Quit_Click"/> ????????????????</StackPanel> ??????????????</StackPanel> ??????????</Border> ?????</wpfdev:NotifyIcon.ContextContent> ?</wpfdev:NotifyIcon>
3) NotifyIconExample.cs 代碼如下:
ContextMenu
使用如下:
?private?void?Quit_Click(object?sender,?RoutedEventArgs?e) ????????{ ????????????Application.Current.Shutdown(); ????????} ????????private?void?SendMessage_Click(object?sender,?RoutedEventArgs?e) ????????{ ????????????NotifyIcon.ShowBalloonTip("Message",?"?Welcome?to?WPFDevelopers.Minimal?",?NotifyIconInfoType.None); ????????}
ContextContent
使用如下:
?private?void?Quit_Click(object?sender,?RoutedEventArgs?e) ????????{ ????????????Application.Current.Shutdown(); ????????} ????????private?void?SendMessage_Click(object?sender,?RoutedEventArgs?e) ????????{ ????????????NotifyIcon.ShowBalloonTip("Message",?"?Welcome?to?WPFDevelopers.Minimal?",?NotifyIconInfoType.None); ????????}
實(shí)現(xiàn)效果
以上就是WPF實(shí)現(xiàn)基礎(chǔ)控件之托盤的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于WPF托盤的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Unity實(shí)現(xiàn)倒計(jì)時(shí)組件
這篇文章主要介紹了Unity實(shí)現(xiàn)倒計(jì)時(shí)組件的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05C# 文件上傳下載(Excel導(dǎo)入,多線程下載)功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了C# 文件上傳下載(Excel導(dǎo)入,多線程下載)功能的實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-08-08C#實(shí)現(xiàn)Winform小數(shù)字鍵盤模擬器
本文主要介紹了C#實(shí)現(xiàn)Winform小數(shù)字鍵盤模擬器,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11C# 使用相同權(quán)限調(diào)用 cmd 傳入命令的方法
本文告訴大家如何使用相同權(quán)限調(diào)用cmd并且傳入命令,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-07-07C#使用smtp發(fā)送帶附件的郵件實(shí)現(xiàn)方法
這篇文章主要介紹了C#使用smtp發(fā)送帶附件的郵件實(shí)現(xiàn)方法,可直接將string類型結(jié)果保存為附件,實(shí)例中備有相應(yīng)的注釋便于理解,需要的朋友可以參考下2014-11-11C#運(yùn)行程序時(shí)阻止關(guān)閉顯示器和系統(tǒng)待機(jī)
這篇文章介紹了C#運(yùn)行程序時(shí)阻止關(guān)閉顯示器和系統(tǒng)待機(jī)的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06