[C.C++] WPF实现基础控件之托盘的示例代码

1898 0
王子 2022-11-5 08:40:14 | 显示全部楼层 |阅读模式
WPF 基础控件之托盘
框架使用大于等于.NET40。
Visual Studio 2022。
项目使用 MIT 开源许可协议。
新建NotifyIcon自定义控件继承自FrameworkElement。
创建托盘程序主要借助与 Win32API:
    注册窗体对象RegisterClassEx。注册消息获取对应消息标识Id RegisterWindowMessage。创建窗体(本质上托盘在创建时需要一个窗口句柄,完全可以将主窗体的句柄给进去,但是为了更好的管理消息以及托盘的生命周期,通常会创建一个独立不可见的窗口)CreateWindowEx。
以下2点需要注意:
    托盘控件的ContextMenu菜单MenuItem 在使用binding时无效,是因为DataContext没有带过去,需要重新赋值一次。托盘控件发送ShowBalloonTip消息通知时候需新建Shell_NotifyIcon。Nuget 最新 Install-Package WPFDevelopers 1.0.9.1-preview


示例代码
1) NotifyIcon.cs 代码如下:
  1. usingSystem;
  2. usingSystem.IO;
  3. usingSystem.Runtime.InteropServices;
  4. usingSystem.Threading;
  5. usingSystem.Windows;
  6. usingSystem.Windows.Controls;
  7. usingSystem.Windows.ontrols.Primitives;
  8. usingSystem.Windows.Data;
  9. usingSystem.Windows.Input;
  10. usingSystem.Windows.Media;
  11. usingSystem.Windows.Media.Imaging;
  12. usingWPFDevelopers.Controls.Runtimes;
  13. usingWPFDevelopers.Controls.Runtimes.Interop;
  14. usingWPFDevelopers.Controls.Runtimes.Shell32;
  15. usingWPFDevelopers.Controls.Runtimes.User32;
  16. namespaceWPFDevelopers.Controls
  17. {
  18. publicclassNotifyIcon:FrameworkElement,IDisposable
  19. {
  20. privatestaticNotifyIconNotifyIconCache;
  21. publicstaticreadonlyDependencyPropertyContextContentProperty=DependencyProperty.Register(
  22. "ContextContent",typeof(object),typeof(NotifyIcon),newPropertyMetadata(default));
  23. publicstaticreadonlyDependencyPropertyIconProperty=
  24. DependencyProperty.Register("Icon",typeof(ImageSource),typeof(NotifyIcon),
  25. newPropertyMetadata(default,OnIconPropertyChanged));
  26. publicstaticreadonlyDependencyPropertyTitleProperty=
  27. DependencyProperty.Register("Title",typeof(string),typeof(NotifyIcon),
  28. newPropertyMetadata(default,OnTitlePropertyChanged));
  29. publicstaticreadonlyRoutedEventClickEvent=
  30. EventManager.RegisterRoutedEvent("Click",RoutingStrategy.Bubble,
  31. typeof(RoutedEventHandler),typeof(NotifyIcon));
  32. publicstaticreadonlyRoutedEventMouseDoubleClickEvent=
  33. EventManager.RegisterRoutedEvent("MouseDoubleClick",RoutingStrategy.Bubble,
  34. typeof(RoutedEventHandler),typeof(NotifyIcon));
  35. privatestaticbools_Loaded=false;
  36. privatestaticNotifyIcons_NotifyIcon;
  37. //这是窗口名称
  38. privatereadonlystring_TrayWndClassName;
  39. //这个是窗口消息名称
  40. privatereadonlystring_TrayWndMessage;
  41. //这个是窗口消息回调(窗口消息都需要在此捕获)
  42. privatereadonlyWndProc_TrayWndProc;
  43. privatePopup_contextContent;
  44. privatebool_doubleClick;
  45. //图标句柄
  46. privateIntPtr_hIcon=IntPtr.Zero;
  47. privateImageSource_icon;
  48. privateIntPtr_iconHandle;
  49. privateint_IsShowIn;
  50. //托盘对象
  51. privateNOTIFYICONDATA_NOTIFYICONDATA;
  52. //这个是传递给托盘的鼠标消息id
  53. privateint_TrayMouseMessage;
  54. //窗口句柄
  55. privateIntPtr_TrayWindowHandle=IntPtr.Zero;
  56. //通过注册窗口消息可以获取唯一标识Id
  57. privateint_WmTrayWindowMessage;
  58. privatebooldisposedValue;
  59. publicNotifyIcon()
  60. {
  61. _TrayWndClassName=$"WPFDevelopers_{Guid.NewGuid()}";
  62. _TrayWndProc=WndProc_CallBack;
  63. _TrayWndMessage="TrayWndMessageName";
  64. _TrayMouseMessage=(int)WM.USER+1024;
  65. Start();
  66. if(Application.Current!=null)
  67. {
  68. //Application.Current.MainWindow.Closed+=(s,e)=>Dispose();
  69. Application.Current.Exit+=(s,e)=>Dispose();
  70. }
  71. NotifyIconCache=this;
  72. }
  73. staticNotifyIcon()
  74. {
  75. DataContextProperty.OverrideMetadata(typeof(NotifyIcon),newFrameworkPropertyMetadata(DataContextPropertyChanged));
  76. ContextMenuProperty.OverrideMetadata(typeof(NotifyIcon),newFrameworkPropertyMetadata(ContextMenuPropertyChanged));
  77. }
  78. privatestaticvoidDataContextPropertyChanged(DependencyObjectd,DependencyPropertyChangedEventArgse)=>
  79. ((NotifyIcon)d).OnDataContextPropertyChanged(e);
  80. privatevoidOnDataContextPropertyChanged(DependencyPropertyChangedEventArgse)
  81. {
  82. UpdateDataContext(_contextContent,e.OldValue,e.NewValue);
  83. UpdateDataContext(ContextMenu,e.OldValue,e.NewValue);
  84. }
  85. privatevoidUpdateDataContext(FrameworkElementtarget,objectoldValue,objectnewValue)
  86. {
  87. if(target==null||BindingOperations.GetBindingExpression(target,DataContextProperty)!=null)return;
  88. if(ReferenceEquals(this,target.DataContext)||Equals(oldValue,target.DataContext))
  89. {
  90. target.DataContext=newValue??this;
  91. }
  92. }
  93. privatestaticvoidContextMenuPropertyChanged(DependencyObjectd,DependencyPropertyChangedEventArgse)
  94. {
  95. varctl=(NotifyIcon)d;
  96. ctl.OnContextMenuPropertyChanged(e);
  97. }
  98. privatevoidOnContextMenuPropertyChanged(DependencyPropertyChangedEventArgse)=>
  99. UpdateDataContext((ContextMenu)e.NewValue,null,DataContext);
  100. publicobjectContextContent
  101. {
  102. get=>GetValue(ContextContentProperty);
  103. set=>SetValue(ContextContentProperty,value);
  104. }
  105. publicImageSourceIcon
  106. {
  107. get=>(ImageSource)GetValue(IconProperty);
  108. set=>SetValue(IconProperty,value);
  109. }
  110. publicstringTitle
  111. {
  112. get=>(string)GetValue(TitleProperty);
  113. set=>SetValue(TitleProperty,value);
  114. }
  115. publicvoidDispose()
  116. {
  117. Dispose(true);
  118. GC.SuppressFinalize(this);
  119. }
  120. privatestaticvoidOnTitlePropertyChanged(DependencyObjectd,DependencyPropertyChangedEventArgse)
  121. {
  122. if(disNotifyIcontrayService)
  123. trayService.ChangeTitle(e.NewValue?.ToString());
  124. }
  125. privatestaticvoidOnIconPropertyChanged(DependencyObjectd,DependencyPropertyChangedEventArgse)
  126. {
  127. if(disNotifyIcontrayService)
  128. {
  129. varnotifyIcon=(NotifyIcon)d;
  130. notifyIcon._icon=(ImageSource)e.NewValue;
  131. trayService.ChangeIcon();
  132. }
  133. }
  134. publiceventRoutedEventHandlerClick
  135. {
  136. add=>AddHandler(ClickEvent,value);
  137. remove=>RemoveHandler(ClickEvent,value);
  138. }
  139. publiceventRoutedEventHandlerMouseDoubleClick
  140. {
  141. add=>AddHandler(MouseDoubleClickEvent,value);
  142. remove=>RemoveHandler(MouseDoubleClickEvent,value);
  143. }
  144. privatestaticvoidCurrent_Exit(objectsender,ExitEventArgse)
  145. {
  146. s_NotifyIcon?.Dispose();
  147. s_NotifyIcon=default;
  148. }
  149. publicboolStart()
  150. {
  151. RegisterClass(_TrayWndClassName,_TrayWndProc,_TrayWndMessage);
  152. LoadNotifyIconData(string.Empty);
  153. Show();
  154. returntrue;
  155. }
  156. publicboolStop()
  157. {
  158. //销毁窗体
  159. if(_TrayWindowHandle!=IntPtr.Zero)
  160. if(User32Interop.IsWindow(_TrayWindowHandle))
  161. User32Interop.DestroyWindow(_TrayWindowHandle);
  162. //反注册窗口类
  163. if(!string.IsNullOrWhiteSpace(_TrayWndClassName))
  164. User32Interop.UnregisterClassName(_TrayWndClassName,Kernel32Interop.GetModuleHandle(default));
  165. //销毁Icon
  166. if(_hIcon!=IntPtr.Zero)
  167. User32Interop.DestroyIcon(_hIcon);
  168. Hide();
  169. returntrue;
  170. }
  171. ///<summary>
  172. ///注册并创建窗口对象
  173. ///</summary>
  174. ///<paramname="className">窗口名称</param>
  175. ///<paramname="messageName">窗口消息名称</param>
  176. ///<returns></returns>
  177. privateboolRegisterClass(stringclassName,WndProcwndproccallback,stringmessageName)
  178. {
  179. varwndClass=newWNDCLASSEX
  180. {
  181. cbSize=Marshal.SizeOf(typeof(WNDCLASSEX)),
  182. style=0,
  183. lpfnWndProc=wndproccallback,
  184. cbClsExtra=0,
  185. cbWndExtra=0,
  186. hInstance=IntPtr.Zero,
  187. hCursor=IntPtr.Zero,
  188. hbrBackground=IntPtr.Zero,
  189. lpszMenuName=string.Empty,
  190. lpszClassName=className
  191. };
  192. //注册窗体对象
  193. User32Interop.RegisterClassEx(refwndClass);
  194. //注册消息获取对应消息标识id
  195. _WmTrayWindowMessage=User32Interop.RegisterWindowMessage(messageName);
  196. //创建窗体(本质上托盘在创建时需要一个窗口句柄,完全可以将主窗体的句柄给进去,但是为了更好的管理消息以及托盘的生命周期,通常会创建一个独立不可见的窗口)
  197. _TrayWindowHandle=User32Interop.CreateWindowEx(0,className,"",0,0,0,1,1,IntPtr.Zero,IntPtr.Zero,
  198. IntPtr.Zero,IntPtr.Zero);
  199. returntrue;
  200. }
  201. ///<summary>
  202. ///创建托盘对象
  203. ///</summary>
  204. ///<paramname="icon">图标路径,可以修改托盘图标(本质上是可以接受用户传入一个图片对象,然后将图片转成Icon,但是算了这个有点复杂)</param>
  205. ///<paramname="title">托盘的tooltip</param>
  206. ///<returns></returns>
  207. privateboolLoadNotifyIconData(stringtitle)
  208. {
  209. lock(this)
  210. {
  211. _NOTIFYICONDATA=NOTIFYICONDATA.GetDefaultNotifyData(_TrayWindowHandle);
  212. if(_TrayMouseMessage!=0)
  213. _NOTIFYICONDATA.uCallbackMessage=(uint)_TrayMouseMessage;
  214. else
  215. _TrayMouseMessage=(int)_NOTIFYICONDATA.uCallbackMessage;
  216. if(_iconHandle==IntPtr.Zero)
  217. {
  218. varprocessPath=Kernel32Interop.GetModuleFileName(newHandleRef());
  219. if(!string.IsNullOrWhiteSpace(processPath))
  220. {
  221. varindex=IntPtr.Zero;
  222. varhIcon=Shell32Interop.ExtractAssociatedIcon(IntPtr.Zero,processPath,refindex);
  223. _NOTIFYICONDATA.hIcon=hIcon;
  224. _hIcon=hIcon;
  225. }
  226. }
  227. if(!string.IsNullOrWhiteSpace(title))
  228. _NOTIFYICONDATA.szTip=title;
  229. }
  230. returntrue;
  231. }
  232. privateboolShow()
  233. {
  234. varcommand=NotifyCommand.NIM_Add;
  235. if(Thread.VolatileRead(ref_IsShowIn)==1)
  236. command=NotifyCommand.NIM_Modify;
  237. else
  238. Thread.VolatileWrite(ref_IsShowIn,1);
  239. lock(this)
  240. {
  241. returnShell32Interop.Shell_NotifyIcon(command,ref_NOTIFYICONDATA);
  242. }
  243. }
  244. internalstaticintAlignToBytes(doubleoriginal,intnBytesCount)
  245. {
  246. varnBitsCount=8<<(nBytesCount-1);
  247. return((int)Math.Ceiling(original)+(nBitsCount-1))/nBitsCount*nBitsCount;
  248. }
  249. privatestaticbyte[]GenerateMaskArray(intwidth,intheight,byte[]colorArray)
  250. {
  251. varnCount=width*height;
  252. varbytesPerScanLine=AlignToBytes(width,2)/8;
  253. varbitsMask=newbyte[bytesPerScanLine*height];
  254. for(vari=0;i<nCount;i++)
  255. {
  256. varhPos=i%width;
  257. varvPos=i/width;
  258. varbyteIndex=hPos/8;
  259. varoffsetBit=(byte)(0x80>>(hPos%8));
  260. if(colorArray[i*4+3]==0x00)
  261. bitsMask[byteIndex+bytesPerScanLine*vPos]|=offsetBit;
  262. else
  263. bitsMask[byteIndex+bytesPerScanLine*vPos]&=(byte)~offsetBit;
  264. if(hPos==width-1&&width==8)bitsMask[1+bytesPerScanLine*vPos]=0xff;
  265. }
  266. returnbitsMask;
  267. }
  268. privatebyte[]BitmapImageToByteArray(BitmapImagebmp)
  269. {
  270. byte[]bytearray=null;
  271. try
  272. {
  273. varsmarket=bmp.StreamSource;
  274. if(smarket!=null&&smarket.Length>0)
  275. {
  276. //设置当前位置
  277. smarket.Position=0;
  278. using(varbr=newBinaryReader(smarket))
  279. {
  280. bytearray=br.ReadBytes((int)smarket.Length);
  281. }
  282. }
  283. }
  284. catch(Exceptionex)
  285. {
  286. }
  287. returnbytearray;
  288. }
  289. privatebyte[]ConvertBitmapSourceToBitmapImage(
  290. BitmapSourcebitmapSource)
  291. {
  292. byte[]imgByte=default;
  293. if(!(bitmapSourceisBitmapImagebitmapImage))
  294. {
  295. bitmapImage=newBitmapImage();
  296. varencoder=newBmpBitmapEncoder();
  297. encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
  298. using(varmemoryStream=newMemoryStream())
  299. {
  300. encoder.Save(memoryStream);
  301. memoryStream.Position=0;
  302. bitmapImage.BeginInit();
  303. bitmapImage.CacheOption=BitmapCacheOption.OnLoad;
  304. bitmapImage.StreamSource=memoryStream;
  305. bitmapImage.EndInit();
  306. imgByte=BitmapImageToByteArray(bitmapImage);
  307. }
  308. }
  309. returnimgByte;
  310. }
  311. internalstaticIconHandleCreateIconCursor(byte[]xor,intwidth,intheight,intxHotspot,
  312. intyHotspot,boolisIcon)
  313. {
  314. varbits=IntPtr.Zero;
  315. BitmapHandlecolorBitmap=null;
  316. varbi=newBITMAPINFO(width,-height,32)
  317. {
  318. bmiHeader_biCompression=0
  319. };
  320. colorBitmap=Gdi32Interop.CreateDIBSection(newHandleRef(null,IntPtr.Zero),refbi,0,refbits,null,0);
  321. if(colorBitmap.IsInvalid||bits==IntPtr.Zero)returnIconHandle.GetInvalidIcon();
  322. Marshal.Copy(xor,0,bits,xor.Length);
  323. varmaskArray=GenerateMaskArray(width,height,xor);
  324. varmaskBitmap=Gdi32Interop.CreateBitmap(width,height,1,1,maskArray);
  325. if(maskBitmap.IsInvalid)returnIconHandle.GetInvalidIcon();
  326. variconInfo=newGdi32Interop.ICONINFO
  327. {
  328. fIcon=isIcon,
  329. xHotspot=xHotspot,
  330. yHotspot=yHotspot,
  331. hbmMask=maskBitmap,
  332. hbmColor=colorBitmap
  333. };
  334. returnUser32Interop.CreateIconIndirect(iconInfo);
  335. }
  336. privateboolChangeIcon()
  337. {
  338. varbitmapFrame=_iconasBitmapFrame;
  339. if(bitmapFrame!=null&&bitmapFrame.Decoder!=null)
  340. if(bitmapFrame.DecoderisIconBitmapDecoder)
  341. {
  342. //variconBitmapDecoder=newRect(0,0,_icon.Width,_icon.Height);
  343. //vardv=newDrawingVisual();
  344. //vardc=dv.RenderOpen();
  345. //dc.DrawImage(_icon,iconBitmapDecoder);
  346. //dc.Close();
  347. //varbmp=newRenderTargetBitmap((int)_icon.Width,(int)_icon.Height,96,96,
  348. //PixelFormats.Pbgra32);
  349. //bmp.Render(dv);
  350. //BitmapSourcebitmapSource=bmp;
  351. //if(bitmapSource.Format!=PixelFormats.Bgra32&&bitmapSource.Format!=PixelFormats.Pbgra32)
  352. //bitmapSource=newFormatConvertedBitmap(bitmapSource,PixelFormats.Bgra32,null,0.0);
  353. varw=bitmapFrame.PixelWidth;
  354. varh=bitmapFrame.PixelHeight;
  355. varbpp=bitmapFrame.Format.BitsPerPixel;
  356. varstride=(bpp*w+31)/32*4;
  357. varsizeCopyPixels=stride*h;
  358. varxor=newbyte[sizeCopyPixels];
  359. bitmapFrame.CopyPixels(xor,stride,0);
  360. variconHandle=CreateIconCursor(xor,w,h,0,0,true);
  361. _iconHandle=iconHandle.CriticalGetHandle();
  362. }
  363. if(Thread.VolatileRead(ref_IsShowIn)!=1)
  364. returnfalse;
  365. if(_hIcon!=IntPtr.Zero)
  366. {
  367. User32Interop.DestroyIcon(_hIcon);
  368. _hIcon=IntPtr.Zero;
  369. }
  370. lock(this)
  371. {
  372. if(_iconHandle!=IntPtr.Zero)
  373. {
  374. varhIcon=_iconHandle;
  375. _NOTIFYICONDATA.hIcon=hIcon;
  376. _hIcon=hIcon;
  377. }
  378. else
  379. {
  380. _NOTIFYICONDATA.hIcon=IntPtr.Zero;
  381. }
  382. returnShell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Modify,ref_NOTIFYICONDATA);
  383. }
  384. }
  385. privateboolChangeTitle(stringtitle)
  386. {
  387. if(Thread.VolatileRead(ref_IsShowIn)!=1)
  388. returnfalse;
  389. lock(this)
  390. {
  391. _NOTIFYICONDATA.szTip=title;
  392. returnShell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Modify,ref_NOTIFYICONDATA);
  393. }
  394. }
  395. publicstaticvoidShowBalloonTip(stringtitle,stringcontent,NotifyIconInfoTypeinfoType)
  396. {
  397. if(NotifyIconCache!=null)
  398. NotifyIconCache.ShowBalloonTips(title,content,infoType);
  399. }
  400. publicvoidShowBalloonTips(stringtitle,stringcontent,NotifyIconInfoTypeinfoType)
  401. {
  402. if(Thread.VolatileRead(ref_IsShowIn)!=1)
  403. return;
  404. var_ShowNOTIFYICONDATA=NOTIFYICONDATA.GetDefaultNotifyData(_TrayWindowHandle);
  405. _ShowNOTIFYICONDATA.uFlags=NIFFlags.NIF_INFO;
  406. _ShowNOTIFYICONDATA.szInfoTitle=title??string.Empty;
  407. _ShowNOTIFYICONDATA.szInfo=content??string.Empty;
  408. switch(infoType)
  409. {
  410. caseNotifyIconInfoType.Info:
  411. _ShowNOTIFYICONDATA.dwInfoFlags=NIIFFlags.NIIF_INFO;
  412. break;
  413. caseNotifyIconInfoType.Warning:
  414. _ShowNOTIFYICONDATA.dwInfoFlags=NIIFFlags.NIIF_WARNING;
  415. break;
  416. caseNotifyIconInfoType.Error:
  417. _ShowNOTIFYICONDATA.dwInfoFlags=NIIFFlags.NIIF_ERROR;
  418. break;
  419. caseNotifyIconInfoType.None:
  420. _ShowNOTIFYICONDATA.dwInfoFlags=NIIFFlags.NIIF_NONE;
  421. break;
  422. }
  423. Shell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Modify,ref_ShowNOTIFYICONDATA);
  424. }
  425. privateboolHide()
  426. {
  427. varisShow=Thread.VolatileRead(ref_IsShowIn);
  428. if(isShow!=1)
  429. returntrue;
  430. Thread.VolatileWrite(ref_IsShowIn,0);
  431. lock(this)
  432. {
  433. returnShell32Interop.Shell_NotifyIcon(NotifyCommand.NIM_Delete,ref_NOTIFYICONDATA);
  434. }
  435. }
  436. privateIntPtrWndProc_CallBack(IntPtrhwnd,WMmsg,IntPtrwParam,IntPtrlParam)
  437. {
  438. //这是窗口相关的消息
  439. if((int)msg==_WmTrayWindowMessage)
  440. {
  441. }
  442. elseif((int)msg==_TrayMouseMessage)//这是托盘上鼠标相关的消息
  443. {
  444. switch((WM)(long)lParam)
  445. {
  446. caseWM.LBUTTONDOWN:
  447. break;
  448. caseWM.LBUTTONUP:
  449. WMMouseUp(MouseButton.Left);
  450. break;
  451. caseWM.LBUTTONDBLCLK:
  452. WMMouseDown(MouseButton.Left,2);
  453. break;
  454. caseWM.RBUTTONDOWN:
  455. break;
  456. caseWM.RBUTTONUP:
  457. OpenMenu();
  458. break;
  459. caseWM.MOUSEMOVE:
  460. break;
  461. caseWM.MOUSEWHEEL:
  462. break;
  463. }
  464. }
  465. elseif(msg==WM.COMMAND)
  466. {
  467. }
  468. returnUser32Interop.DefWindowProc(hwnd,msg,wParam,lParam);
  469. }
  470. privatevoidWMMouseUp(MouseButtonbutton)
  471. {
  472. if(!_doubleClick&&button==MouseButton.Left)
  473. RaiseEvent(newMouseButtonEventArgs(
  474. Mouse.PrimaryDevice,
  475. Environment.TickCount,button)
  476. {
  477. RoutedEvent=ClickEvent
  478. });
  479. _doubleClick=false;
  480. }
  481. privatevoidWMMouseDown(MouseButtonbutton,intclicks)
  482. {
  483. if(clicks==2)
  484. {
  485. RaiseEvent(newMouseButtonEventArgs(
  486. Mouse.PrimaryDevice,
  487. Environment.TickCount,button)
  488. {
  489. RoutedEvent=MouseDoubleClickEvent
  490. });
  491. _doubleClick=true;
  492. }
  493. }
  494. privatevoidOpenMenu()
  495. {
  496. if(ContextContent!=null)
  497. {
  498. _contextContent=newPopup
  499. {
  500. Placement=PlacementMode.Mouse,
  501. AllowsTransparency=true,
  502. StaysOpen=false,
  503. UseLayoutRounding=true,
  504. SnapsToDevicePixels=true
  505. };
  506. _contextContent.Child=newContentControl
  507. {
  508. Content=ContextContent
  509. };
  510. UpdateDataContext(_contextContent,null,DataContext);
  511. _contextContent.IsOpen=true;
  512. User32Interop.SetForegroundWindow(_contextContent.Child.GetHandle());
  513. }
  514. elseif(ContextMenu!=null)
  515. {
  516. if(ContextMenu.Items.Count==0)return;
  517. ContextMenu.InvalidateProperty(StyleProperty);
  518. foreach(variteminContextMenu.Items)
  519. if(itemisMenuItemmenuItem)
  520. {
  521. menuItem.InvalidateProperty(StyleProperty);
  522. }
  523. else
  524. {
  525. varcontainer=ContextMenu.ItemContainerGenerator.ContainerFromItem(item)asMenuItem;
  526. container?.InvalidateProperty(StyleProperty);
  527. }
  528. ContextMenu.Placement=PlacementMode.Mouse;
  529. ContextMenu.IsOpen=true;
  530. User32Interop.SetForegroundWindow(ContextMenu.GetHandle());
  531. }
  532. }
  533. protectedvirtualvoidDispose(booldisposing)
  534. {
  535. if(!disposedValue)
  536. {
  537. if(disposing)
  538. Stop();
  539. disposedValue=true;
  540. }
  541. }
  542. }
  543. publicenumNotifyIconInfoType
  544. {
  545. ///<summary>
  546. ///NoIcon.
  547. ///</summary>
  548. None,
  549. ///<summary>
  550. ///AInformationIcon.
  551. ///</summary>
  552. Info,
  553. ///<summary>
  554. ///AWarningIcon.
  555. ///</summary>
  556. Warning,
  557. ///<summary>
  558. ///AErrorIcon.
  559. ///</summary>
  560. Error
  561. }
  562. }
复制代码
2) NotifyIconExample.xaml 代码如下:
ContextMenu 使用如下:
  1. <wpfdev:NotifyIconTitle="WPF开发者">
  2. <wpfdev:NotifyIcon.ContextMenu>
  3. <ContextMenu>
  4. <MenuItemHeader="托盘消息"Click="SendMessage_Click"/>
  5. <MenuItemHeader="退出"Click="Quit_Click"/>
  6. </ContextMenu>
  7. </wpfdev:NotifyIcon.ContextMenu>
  8. </wpfdev:NotifyIcon>
复制代码
ContextContent 使用如下:
  1. <wpfdev:NotifyIconTitle="WPF开发者">
  2. <wpfdev:NotifyIco.ContextContent>
  3. <BorderCornerRadius="3"Margin="10"
  4. Background="{DynamicResourceBackgroundSolidColorBrush}"
  5. Effect="{StaticResourceNormalShadowDepth}">
  6. <StackPanelVerticalAlignment="Center"Margin="16">
  7. <RectangleWidth="100"Height="100">
  8. <Rectangle.Fill>
  9. <ImageBrushImageSource="pack://application:,,,/Logo.ico"/>
  10. </Rectangle.Fill>
  11. </Rectangle>
  12. <StackPanelMargin="0,16,0,0"HorizontalAlignment="Center"Orientation="Horizontal">
  13. <ButtonMinWidth="100"Content="关于"
  14. Style="{DynamicResourcePrimaryButton}"
  15. Command="{BindingGithubCommand}"/>
  16. <ButtonMargin="16,0,0,0"MinWidth="100"Content="退出"Click="Quit_Click"/>
  17. </StackPanel>
  18. </StackPanel>
  19. </Border>
  20. </wpfdev:NotifyIcon.ContextContent>
  21. </wpfdev:NotifyIcon>
复制代码
3) NotifyIconExample.cs 代码如下:
ContextMenu 使用如下:
  1. privatevoidQuit_Click(objectsender,RoutedEventArgse)
  2. {
  3. Application.Current.Shutdown();
  4. }
  5. privatevoidSendMessage_Click(objectsender,RoutedEventArgse)
  6. {
  7. NotifyIcon.ShowBalloonTip("Message","WelcometoWPFDevelopers.Minimal",NotifyIconInfoType.None);
  8. }
复制代码
ContextContent 使用如下:
  1. privatevoidQuit_Click(objectsender,RoutedEventArgse)
  2. {
  3. Application.Current.Shutdown();
  4. }
  5. privatevoidSendMessage_Click(objectsender,RoutedEventArgse)
  6. {
  7. NotifyIcon.ShowBalloonTip("Message","WelcometoWPFDevelopers.Minimal",NotifyIconInfoType.None);
  8. }
复制代码
实现效果


以上就是WPF实现基础控件之托盘的示例代码的详细内容,更多关于WPF托盘的资料请关注中国红客联盟其它相关文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行