From 6e56c967ceca9ee6c8d96e367f27825c5d8d48fd Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sat, 30 Mar 2019 23:42:21 +0800 Subject: [PATCH] dev 19-3-30 --- HandyControl/Controls/Other/NotifyIcon.cs | 78 +++++++++++++++--- HandyControl/Tools/Interop/BitmapHandle.cs | 8 ++ HandyControlDemo/HandyControlDemo.csproj | 1 + HandyControlDemo/Resources/Img/icon-white.ico | Bin 0 -> 99678 bytes HandyControlDemo/Resources/Img/icon-white.png | Bin 16561 -> 0 bytes .../Controls/NotifyIconDemoCtl.xaml | 49 ++++++++--- .../Controls/NotifyIconDemoViewModel.cs | 38 +++++++-- 7 files changed, 147 insertions(+), 27 deletions(-) create mode 100644 HandyControlDemo/Resources/Img/icon-white.ico delete mode 100644 HandyControlDemo/Resources/Img/icon-white.png diff --git a/HandyControl/Controls/Other/NotifyIcon.cs b/HandyControl/Controls/Other/NotifyIcon.cs index eb263959..64c2e802 100644 --- a/HandyControl/Controls/Other/NotifyIcon.cs +++ b/HandyControl/Controls/Other/NotifyIcon.cs @@ -5,6 +5,7 @@ using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; +using System.Windows.Threading; using HandyControl.Data; using HandyControl.Tools; using HandyControl.Tools.Interop; @@ -45,6 +46,10 @@ namespace HandyControl.Controls private bool _doubleClick; + private DispatcherTimer _dispatcherTimer; + + private bool _isTransparent; + static NotifyIcon() { VisibilityProperty.OverrideMetadata(typeof(NotifyIcon), new PropertyMetadata(Visibility.Visible, OnVisibilityChanged)); @@ -111,6 +116,12 @@ namespace HandyControl.Controls ctl.OnIconChanged(); } + public ImageSource Icon + { + get => (ImageSource)GetValue(IconProperty); + set => SetValue(IconProperty, value); + } + public static readonly DependencyProperty ContextContentProperty = DependencyProperty.Register( "ContextContent", typeof(object), typeof(NotifyIcon), new PropertyMetadata(default(object))); @@ -120,8 +131,56 @@ namespace HandyControl.Controls set => SetValue(ContextContentProperty, value); } + public static readonly DependencyProperty BlinkIntervalProperty = DependencyProperty.Register( + "BlinkInterval", typeof(TimeSpan), typeof(NotifyIcon), new PropertyMetadata(TimeSpan.FromMilliseconds(500), OnBlinkIntervalChanged)); + + private static void OnBlinkIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (NotifyIcon)d; + if (ctl._dispatcherTimer != null) + { + ctl._dispatcherTimer.Interval = (TimeSpan) e.NewValue; + } + } + + public TimeSpan BlinkInterval + { + get => (TimeSpan) GetValue(BlinkIntervalProperty); + set => SetValue(BlinkIntervalProperty, value); + } + public static readonly DependencyProperty IsBlinkProperty = DependencyProperty.Register( - "IsBlink", typeof(bool), typeof(NotifyIcon), new PropertyMetadata(ValueBoxes.FalseBox)); + "IsBlink", typeof(bool), typeof(NotifyIcon), new PropertyMetadata(ValueBoxes.FalseBox, OnIsBlinkChanged)); + + private static void OnIsBlinkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (NotifyIcon)d; + if (ctl.Visibility != Visibility.Visible) return; + if ((bool) e.NewValue) + { + if (ctl._dispatcherTimer == null) + { + ctl._dispatcherTimer = new DispatcherTimer + { + Interval = ctl.BlinkInterval + }; + ctl._dispatcherTimer.Tick += ctl.DispatcherTimer_Tick; + } + ctl._dispatcherTimer.Start(); + } + else + { + ctl._dispatcherTimer?.Stop(); + ctl._dispatcherTimer = null; + ctl.UpdateIcon(true); + } + } + + private void DispatcherTimer_Tick(object sender, EventArgs e) + { + if (Visibility != Visibility.Visible || _currentSmallIconHandle == null) return; + UpdateIcon(true, !_isTransparent); + } public bool IsBlink { @@ -129,12 +188,6 @@ namespace HandyControl.Controls set => SetValue(IsBlinkProperty, value); } - public ImageSource Icon - { - get => (ImageSource)GetValue(IconProperty); - set => SetValue(IconProperty, value); - } - private void OnIconChanged() { IconHandle largeIconHandle; @@ -173,12 +226,13 @@ namespace HandyControl.Controls _currentSmallIconHandle = smallIconHandle; } - private void UpdateIcon(bool showIconInTray) + private void UpdateIcon(bool showIconInTray, bool isTransparent = false) { lock (_syncObj) { - if (DesignerHelper.IsInDesignMode) return; + if (_currentSmallIconHandle == null || DesignerHelper.IsInDesignMode) return; + _isTransparent = isTransparent; var data = new NOTIFYICONDATA { uCallbackMessage = WmTrayMouseMessage, @@ -187,7 +241,7 @@ namespace HandyControl.Controls uTimeoutOrVersion = 10, uID = _id, dwInfoFlags = NativeMethods.NIF_TIP, - hIcon = _currentSmallIconHandle.CriticalGetHandle(), + hIcon = isTransparent ? IntPtr.Zero : _currentSmallIconHandle.CriticalGetHandle(), szTip = Text }; @@ -397,6 +451,10 @@ namespace HandyControl.Controls { if (disposing) { + if (_dispatcherTimer != null && IsBlink) + { + _dispatcherTimer.Stop(); + } UpdateIcon(false); _defaultLargeIconHandle?.Dispose(); _defaultSmallIconHandle?.Dispose(); diff --git a/HandyControl/Tools/Interop/BitmapHandle.cs b/HandyControl/Tools/Interop/BitmapHandle.cs index 2970e514..1e893fa9 100644 --- a/HandyControl/Tools/Interop/BitmapHandle.cs +++ b/HandyControl/Tools/Interop/BitmapHandle.cs @@ -1,12 +1,20 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security; namespace HandyControl.Tools.Interop { + [SuppressMessage("ReSharper", "UnusedMember.Local")] internal sealed class BitmapHandle : WpfSafeHandle { + [SecurityCritical] + private BitmapHandle() : this(true) + { + //请不要删除此构造函数,否则当使用自定义ico文件时会报错 + } + [SecurityCritical] private BitmapHandle(bool ownsHandle) : base(ownsHandle, CommonHandles.GDI) { diff --git a/HandyControlDemo/HandyControlDemo.csproj b/HandyControlDemo/HandyControlDemo.csproj index 53deb9f4..cbbb9f37 100644 --- a/HandyControlDemo/HandyControlDemo.csproj +++ b/HandyControlDemo/HandyControlDemo.csproj @@ -805,6 +805,7 @@ TextTemplatingFileGenerator MessageToken.cs + diff --git a/HandyControlDemo/Resources/Img/icon-white.ico b/HandyControlDemo/Resources/Img/icon-white.ico new file mode 100644 index 0000000000000000000000000000000000000000..a90a5b46828516d6856396b4a348664538ecf932 GIT binary patch literal 99678 zcmeI53Ah|ZxrS$w5W*J1z9uJuunDqbkR>PVi-7F#T;UqbmBq+n1eeQ_Lr_6cARwR! zgrI_KiY#(PBmqPalr`*x90(+VpzI_-Aouwlg%HN92+|NnJW zS9i~u6bi+{5`{s73Y0?&$M!1}4lNW4Lx=V(|Bm%{vu^XvOUvsO3P-O}D2y7_v%KNX zg~Gt?3x%$(((-^};R~l13L8=fhf-tDdWu4UdhQ$8gSX5-3l}bY3>q~Z`&re&|6zGn z!1|9^_X^AhW7WrYvtduz15}T(PxvqahQnXX%7F43))iqxnC;sxf7S=Zd!286^~Xu9 z&^{Z1|9JU56jXPV<3GoKbHJGY`0LHefbvS#sr_MaCp=Q(cFHwD?cV@lb_E->PhVIb z29+2{*$1@#MhG)=d_Q(r1J*9FI;D=Scl_n-Bmb4_hoQT~{gi8ge7Fh1%pAW7JG}1O z>193-fqKXPihb06qsL!XI({2U|M{o(2g4F@2ZWh)+6ttj|J9k3}%~IHl9HcpCiUddTjft5wfr*aB9D zaZs;5_0Kb49as}4L8Epn2dZ6-9pVe{CWM*#=MO>SfjQr%sScS+(D+xYeVr%kYG2JNb^cXfH&|8Ir2oO-k0na`!>W$?2Fs1K|3N_e+p?}+ z{5IP^s4A8XSiS~s1C0%Sv`%ByYT(b=Se6@&|G=ucG|yTFmJLDMG#B!>|4o(?x9?RL z^B?&EYCp<#hTSSm`X2x>TV1rfj)mhPar>pZ`crDotLsV-(q0;QPN;-N+kc;9_phpJ zOO`eF*R^$e6*E}=J7_-bZ~p|A8;L)t{q3o%dY;Ovvc1ZuAz-WhFIUyI1IzyTH;Waf z_6I{dwSOZ1G@AeYs$$uZCG=Z5WEXT8QhZ~QOSrSazWI>+ez_pX1X zV|2aNJw_v@b5_^0twH@zZP%N}DL1Es#;GyzC?qk>f!_pa5!K|wT&Q=SVCrk6Z<=G1 zmTJ3EeUi4V8Hjp)V%LW36^_!icwHC>nipIPjcBQN7C(WFK<^ILfQisZ zT^v@|l=Fk3FEBEfpFin-D9&7f-50(AN5hg}=42|j1I;aL+ox2h@k;MXJl}o(YySQ= zL^aiQDJ%umb?KStOJLhHhuj9dT$x5o%Ofe{`2P<3@1|q@R;o*L#2H}Q{zZiwfWJwj zdnfDT_^Qove@JzvjW^=aD8MsvG2gH`q4$AC|LGY>Vr^cRyo% zS4kaWD`>U4|GF>Nb<(!g@_!c^i<|!rj%lU;576GaA#K|BU)M_8rf0Ze{_o1RxcMK# zF+us)HNMsUYyLP9E{n){?5BIzF#lg;n{B(F3d8c>hiwBu^RXys-y*cy|HZEP6%Hg^ zP&}Y_p|ilY{f!Ep|1~rsKPLaPZ6}}l?t@`!qgkf9LFZ4){4cfHpK>KwIU*W+)aNTw zp=B5W&G7$T>Rl}Vr8YY$r$Ki_bT6d$m0|wRVViA}|3e|D&AnLvZj1(X@2>YAL3Jtr zy}^GyD`}eyh~-Z4ftK`mT%4 zbAMgKS)L4WbY%C)_Az_@8b-lL_&zA_pFvzxymx@+eR|(=BIxzIJH6j(E3U8}izN^@plEKewFRW~~AB9q!g<`k-7+5GyRoS5Fds?HQ3(DWq zVny}eld)OX%H`k!cn-2|iczsH=ZifLaaZfAn2qk$+w!uk^Wgcs1RD@%9?$!LG`LkR z16DGi`yRcIeiY)~yGC`u%(L$1fM$FjFRCB@{id^U1n@=l9^>=IVDo*a@_7Xe^|hgQ zO&Y_~w7Y2Bn@bqKOv(C_Ejc!ydiFE*`b*aLgE-%Du;h|g%|H2Ti5YxWSj~^_PwQ68`{Qk8Vg!&Peky`M*IgvXlF{RgQva85&Y`3 z;Md>??M$)IPTVRkjo_D_i6*s`BD6C#X(J6Be@O(tS`~j9<6o5cZH)gbM#!_iL(yux zID%h0TW~5${LOkdQ_KCIM~HuyS`|dxwnBt<(un_}2!7d!e^7*W^c}!f+l3MQ+SP(n zQR3HkP+M&iBgDU(1*eve(2njoTW#$Wzuu9y+AfHo%kCDO;+H0C8*Myjp`Ex@oL}23 z@4jS@xRnO%->&hW*P{3XpDp;?CTIT$$Xl~l{mkz}&}SUj(}EMr2G#9fM;i}WXeVwJ zQQ}{pN`H`$(B~^A2h{&?T<0z9|5MX`+9k2*IaI6d+_d91?Gtz!@&ClMpLR+7`rdx4 z?Z;`yZQ3XBM_L^`?d3iGb4>ozF402on_6vWryaLxpTP4T|6{EdpZ0!a@*h^RkLG`G zCuBfa{boJ&KMt+7ADZ^VN*vPPA0)LX^S^eD|I0~(=lI|sBJ(Akee`|nR@)DJE(CtW zq5Um5wM1a$zLm7muJIqxqWGV*&`#Vc&hkkR_>l?^j9Y2I{`_wvwT)w@1svDxRTFA^ z0#DW;lXh$4cNbrsV}VLm^9+=3iHRT z$FD;I;)%PeXzB|qsqpEzm0H-pE6g9Wo;D7(&`y;2^*3a#w(%y;uo8z3OX^fu-Tw8o z(XR0y-lF)QP1;Ta$DiTXAm}r7CXN5Ipn9v<(M}ri^S`6jHvCHZ{l~iT(}unSn#T7Z zqr`tRz9q3wYiHP-V{M+Kfdt2%R?9c)9Rd1|WD;9Yr;Q?&-=3s_1jmLx|EEs<28*pe z8T$Pf+8CF>|D=cNo^!E#Q`T((Gr*P|S$z&r@c=m6Rs#v@xr1Z%9kn*m2g|!*+t2%+jz=i+9lC0lpl?jP4wUMi~1KUNuTnj zpOGqZ3&h7lalV(@f_@d_dn_lkuAbwI`ke^xGiN~gcOv*y{W}q4PyIybep}yb8w-;` z-@Vm*RP$74y)y&SP8v!}X)0}{v9vb2s~iaWyIwulIv?%?J$u*h5`F~EdS?ctoivn| z(p1_?V`(kTO~2Rjsi6B_y>rm-^}P%8p;>?LPSwtuoB?Sk4W*?tmA2AYT1#^?=Ifl$ zdOdGl0M4?R0ck6ZrL{CS*L#f%IyaI&*QE+)ZJq&XEUl&aShyN=ZI}bj@{s{)EzLD2 zd=PX#r17qeW}T&w0cou{q3#P_g}I=4g0p;NKw9g*z}(;KKEciN^P#<>l-AOGo)(`O|oiH?x5Vh0J@g8iz$|u;ji#B_zLJdoxQw zFxx3L?p+4cLFZD|?M(ul3a7({;N{7bCO_4s*-okJ>Bev(XwI0HX}p$R8oQ4HX)oVu z>TcpP`%!)#H1~ND-i55&vjlh+jDnRQZoZUb&8tp;$004#vz+HZeRoG#3hMUz5dF{R zSe?sR*I(DSdqHy^UB@*C>aF^}j_-ehaWFh;968osbH2H7J*dBEUhHYFvYz?&ZI}N4 zB0j0#?gN^~M>>y9oMwMYjsL1A>*K%1OO5?Mhs~hTd`W*@|I;4-HC}%UHihM&(RlKr z|9{Alo^_oG<$0g!5A{luUrM9@iF}p@Y1uz%_()h2mIS9iNvL6Our)E;OpY#@cq!{{j5i4)6V_hEf*SPKUU!=e0 zj}yV^U!&8IAJbpV_@9;jZ}iu*Y}fxo&VefZb^{20{# zrN8Ep?Qs2f`XfXH)BNui(Dh&M{5(BtNM5nY>`$3h{hubbtdIZF{{%>?zsAgV=>K2B z4;%geBI?Py{z!y`^#3NYCh7kJIbQmI8`8f1 z+vxv_#pz#buw)xKGPH~S_v4fFFMo$gK1MZPJVt+gHzMof{~w4^{ePH=zkz&7|IH!o z{xALa0vq~YOg(wge=M=u(EnuWNpt+St-roYnuq>xOaH9(f2V(qivfMZfBo0^pQZkP z3GrlI|5?QNd$7^}w`e2%m%tZuZq_)1D>wO$(fm*PKMx;3R?X=D4FXJh{cjij_aqjl zf3!2!w*IHk?6hc2H)Su)|D68OQ!D*%0vr8*OX|sr{+i2N3V9g+rT=k|bo_58{VRT} zpzU`UHmoBEso zrJx8-f09tgjQ+>4-%#*!R-?;jdXtHtQrG{>AP@cjdg65Yb7qqVgVR6LJv}%$pZFvp)a3ju@T(mE*tk{}tp#|F08k2e|oPPY#^^!I#KPuQlgC zrO|%|pYt&OyZ#?M{%2kPS2@3R{dfB3SARV>cls}`|K;Rm24s2sSO1s({{tQ1=6{Rk ze|gbg@6Me5`R)Hsf3%mG@sCpTfA#-vmEDLLa z-kod@+qDq2CpH0n7tOC_N!|K|?>K#z@e0UG|4*v_GURG~I23*Xe}?~qKeY(8btjw) z8oQIe|2O)-OkG(Y|F0oN>96l=G}`|MaqKqmU3d&Wg$3|Yi%@&ADX=rx>i>DsU*FYA zs{aV;_+NMm(z5$#co%T`M^ixaKlOiG`kzW&Pe*IIDSO$}|4KY`{lCVviTs#;rtyDU zXb1gmjsMdB70B}Sev><+^w;<} zAF^tS?>FG|=Sn~x3>yEhg1qQInpl(0|J47_fHcSddue|Z7#+Q`;v!#T!FQbgmi;Qo zgZ{rJ&e7oXUv%C${cH3Svx#%Y^fTT6ng0I_pVKni{a?>Vvwr=z)&KSWRpYHl9P)};FHKpo>DZT&m(!CaRbJ)d>`&x8JY zzHv2t6`cNy&YQgH|KFDM@1mZx`~OIMu+{%xqpmE^|4je4q5qELDogrnTy*-Io4tV2 z*UvQnlm2HyR{Fp6p9NX(|C;C6>i^RJSxC$7rD0p+ztLacVa%$%LSVM^SKgiez3WUd z`X7ngN#_46alG`O0BQFBdrE%9y6-cWHjXv(M$P~8)cH43C@jpxY z?}%nL`hQ;Zzlwa>(7#>Af2Ti!Ml@ajrT-DIHpJ>TW`9ck_U|rmHarh$nXdmf^w-}q z>30$4!pD$Rlm3$+ss5`|$9`}jOoz0rA^maIJMVp^zRP$E=(pcLgRI)i1U3nh>OX`! zMuV=IGa)Urp?_bT-xcnHPtyvdMeW+se?9#DF8l@FXp!$h%}ixw?D3ytO#fek&#S;; z@E~N}jQ(FC(6zzKgSj6LE6skTvLEFLxCHd<_kBpqlIpMTF=^~S4buD`W2^Ef{jY>Z z_3zKIy7nIm8ZULdOmobfLiXIO4n)vj?=N?NQ{f?)2WgIDG~W_?omTFElVLan>TlLlN_WkXR)rC85=;eY z{|TgR((Z83^9cD_FCJaLG~e4Ez6ZC$9LS5kN1)T-0?_~66g6Kvv#)+@NBvFtlJ@Oz zpR8C;fh|G*7g0q#X4zNj`n4CF1^0sbLzbWS6JCYs*_Q6tZiD}VbwTg)^m|SNU@1@@ z)!&D~)^H&F2p$HVKMSB;Y$lHU295=t1O8Z+W?8YQzbh7P*Sz(oFa`9iFK?zkt8-vF zXdW;Q)VJ3M%?FjIEnsgL3lrf^cmdu4Y2Ob09ydJukbk>D=kvE=7uX0oU_FrLd%$sU zDcl9m!kdt%eowd+_C8C}^mb6+R(_6xuY<&mtu&U_(p=i>J1hF0f|hkoXk5^>LHo{yJin(V{9bL+P8v!} zX)0}{v9y-v-uIPCrOpM72V+5VLfseW-f$i`>zx^pcG6HgcT#(Yovsg++=?b}tk zT&!Ho$5OG|i*tyHw)l4C^78YwTwK`Ytu7Qgs+Pxl%S)EG2QPP&w=eYeFE1Cfx!h^u zEyd@SOXttx`Jj`^%G-Muv$O1-@8cK6<1JU857pb>l&~}!Wdn)Sij?(t3WmY*e8R#+}ddlL|%H_WQ55BK?U;qFB literal 0 HcmV?d00001 diff --git a/HandyControlDemo/Resources/Img/icon-white.png b/HandyControlDemo/Resources/Img/icon-white.png deleted file mode 100644 index d0bb47760c2597efdc857303fafce90c2151d651..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16561 zcmeHPJ!lkB5Z;Y{N#KHF7cGL|4@AV^wZa)9Nt6W9G=jgSotj3FG+v=%p%#LTSP5dG zp!idnMg&1Df`y!@AQBrvVj30V`Axi)$KKo9*_rpa-+{?{_ulM$GvAy2z1v(qFgcp* z?e7hOAU8fXau98Sw0kxF-aB>XBbuJmV~3}Mpzj4~cw?|{Ll6uE<0E^f&V^y2FgqK< zC@7c9IW$G+KImp>E6aN%_XIimi^$iW~RF^+}+&gzH*i!#S~je`@JXKpnFaKO|Aa6n)q#?cVK zSs8I)M&e#^T7>|EuWVfn0URV372p*|Ljb2VIl-sdc*XHefQt&?5Fp0U5RkTVG%pT} z2T8m#hI0-9Vw{x*P}VLdu-|Z+_}qXA$iZQ{sy6dV z0PfW2nc>=MSmz_+3h=!PIL|b}VO_lKqC=QT>%^O&nKea0x)UQkimp# zY%>i3ja>~)-a7;^iL#kBQU%!JV~u&eCcvXD`bEYuRwT(rMO<6_N}gVxsXid4Y!FRr z2#9>tYByn0^(6+jzXbJ0fbU~~cx4P$IlGz|$2S2+9^!6O6Chq0FF|HwCJMQ*;iW+m=sR>{lN--AWXb7N~c0nH_KzaksCN%Ft?f_%b<_P2TP=|h1E)zI#As^u6 z2=xC-pg#zmhq{s_IJyNLh%!aL3wjMI7T50&Eh4zL&>rXxsJ6o3qDp9grxzqYLkVL& zR4lFu5C>AP4SlRoy>b!Zb_f7%^j>YdN{K2!_4Y-RGxwAZf^-gV-xsOzwG*AX=#ut2 vl-? - - - - + + + + + + + + + + + + - - - + + + + + + + + + + - - + @@ -27,5 +39,18 @@ - + + + + + + +