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 00000000..a90a5b46 Binary files /dev/null and b/HandyControlDemo/Resources/Img/icon-white.ico differ diff --git a/HandyControlDemo/Resources/Img/icon-white.png b/HandyControlDemo/Resources/Img/icon-white.png deleted file mode 100644 index d0bb4776..00000000 Binary files a/HandyControlDemo/Resources/Img/icon-white.png and /dev/null differ diff --git a/HandyControlDemo/UserControl/Controls/NotifyIconDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/NotifyIconDemoCtl.xaml index 3b701d5d..15ab993d 100644 --- a/HandyControlDemo/UserControl/Controls/NotifyIconDemoCtl.xaml +++ b/HandyControlDemo/UserControl/Controls/NotifyIconDemoCtl.xaml @@ -6,20 +6,32 @@ xmlns:interactivity="clr-namespace:HandyControl.Interactivity;assembly=HandyControl" DataContext="{Binding NotifyIconDemo,Source={StaticResource Locator}}" Background="{DynamicResource RegionBrush}"> - - - - + + + + + + + + + + + + - - - + + + + + + + + + + - - + @@ -27,5 +39,18 @@ - + + + + + + +