No files matched your search
@@ -0,0 +1,451 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
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;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class NotifyIcon : FrameworkElement, IDisposable
|
||||
{
|
||||
private bool _added;
|
||||
|
||||
private readonly object _syncObj = new object();
|
||||
|
||||
private readonly int _id;
|
||||
|
||||
private static int NextId;
|
||||
|
||||
private ImageSource _icon;
|
||||
|
||||
private IconHandle _defaultLargeIconHandle;
|
||||
|
||||
private IconHandle _defaultSmallIconHandle;
|
||||
|
||||
private IconHandle _currentLargeIconHandle;
|
||||
|
||||
private IconHandle _currentSmallIconHandle;
|
||||
|
||||
private const int WmTrayMouseMessage = NativeMethods.WM_USER + 1024;
|
||||
|
||||
private string _windowClassName;
|
||||
|
||||
private int _wmTaskbarCreated;
|
||||
|
||||
private IntPtr _messageWindowHandle;
|
||||
|
||||
private readonly WndProc _callback;
|
||||
|
||||
private Popup _contextContent;
|
||||
|
||||
private bool _doubleClick;
|
||||
|
||||
private DispatcherTimer _dispatcherTimer;
|
||||
|
||||
private bool _isTransparent;
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
static NotifyIcon()
|
||||
{
|
||||
VisibilityProperty.OverrideMetadata(typeof(NotifyIcon), new PropertyMetadata(Visibility.Visible, OnVisibilityChanged));
|
||||
}
|
||||
|
||||
private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NotifyIcon) d;
|
||||
var v = (Visibility)e.NewValue;
|
||||
|
||||
if (v == Visibility.Visible)
|
||||
{
|
||||
if (ctl._currentSmallIconHandle == null)
|
||||
{
|
||||
ctl.OnIconChanged();
|
||||
}
|
||||
ctl.UpdateIcon(true);
|
||||
}
|
||||
else if(ctl._currentSmallIconHandle !=null)
|
||||
{
|
||||
ctl.UpdateIcon(false);
|
||||
}
|
||||
}
|
||||
|
||||
public NotifyIcon()
|
||||
{
|
||||
_id = ++NextId;
|
||||
_callback = Callback;
|
||||
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
RegisterClass();
|
||||
if (Visibility == Visibility.Visible)
|
||||
{
|
||||
OnIconChanged();
|
||||
UpdateIcon(true);
|
||||
}
|
||||
};
|
||||
|
||||
if (Application.Current != null) Application.Current.Exit += (s, e) => Dispose();
|
||||
}
|
||||
|
||||
~NotifyIcon()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
"Text", typeof(string), typeof(NotifyIcon), new PropertyMetadata(default(string)));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string) GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
||||
"Icon", typeof(ImageSource), typeof(NotifyIcon), new PropertyMetadata(default(ImageSource), OnIconChanged));
|
||||
|
||||
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NotifyIcon)d;
|
||||
ctl._icon = (ImageSource)e.NewValue;
|
||||
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)));
|
||||
|
||||
public object ContextContent
|
||||
{
|
||||
get => GetValue(ContextContentProperty);
|
||||
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, 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
|
||||
{
|
||||
get => (bool) GetValue(IsBlinkProperty);
|
||||
set => SetValue(IsBlinkProperty, value);
|
||||
}
|
||||
|
||||
private void OnIconChanged()
|
||||
{
|
||||
IconHandle largeIconHandle;
|
||||
IconHandle smallIconHandle;
|
||||
|
||||
if (_icon != null)
|
||||
{
|
||||
IconHelper.GetIconHandlesFromImageSource(_icon, out largeIconHandle, out smallIconHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_defaultLargeIconHandle == null && _defaultSmallIconHandle == null)
|
||||
{
|
||||
IconHelper.GetDefaultIconHandles(out largeIconHandle, out smallIconHandle);
|
||||
_defaultLargeIconHandle = largeIconHandle;
|
||||
_defaultSmallIconHandle = smallIconHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
largeIconHandle = _defaultLargeIconHandle;
|
||||
smallIconHandle = _defaultSmallIconHandle;
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentLargeIconHandle != null && _currentLargeIconHandle != _defaultLargeIconHandle)
|
||||
{
|
||||
_currentLargeIconHandle.Dispose();
|
||||
}
|
||||
|
||||
if (_currentSmallIconHandle != null && _currentSmallIconHandle != _defaultSmallIconHandle)
|
||||
{
|
||||
_currentSmallIconHandle.Dispose();
|
||||
}
|
||||
|
||||
_currentLargeIconHandle = largeIconHandle;
|
||||
_currentSmallIconHandle = smallIconHandle;
|
||||
}
|
||||
|
||||
private void UpdateIcon(bool showIconInTray, bool isTransparent = false)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (_currentSmallIconHandle == null || DesignerHelper.IsInDesignMode) return;
|
||||
|
||||
_isTransparent = isTransparent;
|
||||
var data = new NOTIFYICONDATA
|
||||
{
|
||||
uCallbackMessage = WmTrayMouseMessage,
|
||||
uFlags = NativeMethods.NIF_MESSAGE | NativeMethods.NIF_ICON | NativeMethods.NIF_TIP,
|
||||
hWnd = _messageWindowHandle,
|
||||
uID = _id,
|
||||
dwInfoFlags = NativeMethods.NIF_TIP,
|
||||
hIcon = isTransparent ? IntPtr.Zero : _currentSmallIconHandle.CriticalGetHandle(),
|
||||
szTip = Text
|
||||
};
|
||||
|
||||
if (showIconInTray)
|
||||
{
|
||||
if (!_added)
|
||||
{
|
||||
UnsafeNativeMethods.Shell_NotifyIcon(NativeMethods.NIM_ADD, data);
|
||||
_added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnsafeNativeMethods.Shell_NotifyIcon(NativeMethods.NIM_MODIFY, data);
|
||||
}
|
||||
}
|
||||
else if (_added)
|
||||
{
|
||||
UnsafeNativeMethods.Shell_NotifyIcon(NativeMethods.NIM_DELETE, data);
|
||||
_added = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterClass()
|
||||
{
|
||||
_windowClassName = $"HandyControl.Controls.NotifyIcon{Guid.NewGuid()}";
|
||||
var wndclass = new WNDCLASS
|
||||
{
|
||||
style = 0,
|
||||
lpfnWndProc = _callback,
|
||||
cbClsExtra = 0,
|
||||
cbWndExtra = 0,
|
||||
hInstance = IntPtr.Zero,
|
||||
hIcon = IntPtr.Zero,
|
||||
hCursor = IntPtr.Zero,
|
||||
hbrBackground = IntPtr.Zero,
|
||||
lpszMenuName = "",
|
||||
lpszClassName = _windowClassName
|
||||
};
|
||||
|
||||
UnsafeNativeMethods.RegisterClass(wndclass);
|
||||
_wmTaskbarCreated = NativeMethods.RegisterWindowMessage("TaskbarCreated");
|
||||
_messageWindowHandle = UnsafeNativeMethods.CreateWindowEx(0, _windowClassName, "", 0, 0, 0, 1, 1,
|
||||
IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
|
||||
private IntPtr Callback(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
|
||||
{
|
||||
if (IsLoaded)
|
||||
{
|
||||
if (msg == _wmTaskbarCreated)
|
||||
{
|
||||
UpdateIcon(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (lparam.ToInt32())
|
||||
{
|
||||
case NativeMethods.WM_LBUTTONDBLCLK:
|
||||
WmMouseDown(MouseButton.Left, 2);
|
||||
break;
|
||||
case NativeMethods.WM_LBUTTONUP:
|
||||
WmMouseUp(MouseButton.Left);
|
||||
break;
|
||||
case NativeMethods.WM_RBUTTONUP:
|
||||
ShowContextMenu();
|
||||
WmMouseUp(MouseButton.Right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UnsafeNativeMethods.DefWindowProc(hWnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
private void WmMouseDown(MouseButton button, int clicks)
|
||||
{
|
||||
if (clicks == 2)
|
||||
{
|
||||
RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, button)
|
||||
{
|
||||
RoutedEvent = MouseDoubleClickEvent
|
||||
});
|
||||
_doubleClick = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void WmMouseUp(MouseButton button)
|
||||
{
|
||||
if (!_doubleClick && button == MouseButton.Left)
|
||||
{
|
||||
RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, button)
|
||||
{
|
||||
RoutedEvent = ClickEvent
|
||||
});
|
||||
}
|
||||
_doubleClick = false;
|
||||
}
|
||||
|
||||
private void ShowContextMenu()
|
||||
{
|
||||
var point = new POINT();
|
||||
UnsafeNativeMethods.GetCursorPos(point);
|
||||
|
||||
if (ContextContent != null)
|
||||
{
|
||||
if (_contextContent == null)
|
||||
{
|
||||
_contextContent = new Popup
|
||||
{
|
||||
Placement = PlacementMode.AbsolutePoint,
|
||||
AllowsTransparency = true,
|
||||
StaysOpen = false
|
||||
};
|
||||
}
|
||||
|
||||
_contextContent.HorizontalOffset = point.x;
|
||||
_contextContent.VerticalOffset = point.y;
|
||||
_contextContent.Child = new ContentControl
|
||||
{
|
||||
Content = ContextContent
|
||||
};
|
||||
_contextContent.IsOpen = true;
|
||||
var handle = IntPtr.Zero;
|
||||
var hwndSource = (HwndSource)PresentationSource.FromVisual(_contextContent.Child);
|
||||
if (hwndSource != null)
|
||||
{
|
||||
handle = hwndSource.Handle;
|
||||
}
|
||||
UnsafeNativeMethods.SetForegroundWindow(handle);
|
||||
}
|
||||
else if (ContextMenu != null)
|
||||
{
|
||||
ContextMenu.Placement = PlacementMode.AbsolutePoint;
|
||||
ContextMenu.HorizontalOffset = point.x;
|
||||
ContextMenu.VerticalOffset = point.y;
|
||||
ContextMenu.IsOpen = true;
|
||||
|
||||
var handle = IntPtr.Zero;
|
||||
var hwndSource = (HwndSource)PresentationSource.FromVisual(ContextMenu);
|
||||
if (hwndSource != null)
|
||||
{
|
||||
handle = hwndSource.Handle;
|
||||
}
|
||||
UnsafeNativeMethods.SetForegroundWindow(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ClickEvent =
|
||||
EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(NotifyIcon));
|
||||
|
||||
public event RoutedEventHandler Click
|
||||
{
|
||||
add => AddHandler(ClickEvent, value);
|
||||
remove => RemoveHandler(ClickEvent, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent MouseDoubleClickEvent =
|
||||
EventManager.RegisterRoutedEvent("MouseDoubleClick", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(NotifyIcon));
|
||||
|
||||
public event RoutedEventHandler MouseDoubleClick
|
||||
{
|
||||
add => AddHandler(MouseDoubleClickEvent, value);
|
||||
remove => RemoveHandler(MouseDoubleClickEvent, value);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
if (disposing)
|
||||
{
|
||||
if (_dispatcherTimer != null && IsBlink)
|
||||
{
|
||||
_dispatcherTimer.Stop();
|
||||
}
|
||||
UpdateIcon(false);
|
||||
_defaultLargeIconHandle?.Dispose();
|
||||
_defaultSmallIconHandle?.Dispose();
|
||||
_currentLargeIconHandle?.Dispose();
|
||||
_currentSmallIconHandle?.Dispose();
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void CloseContextControl()
|
||||
{
|
||||
if (_contextContent != null)
|
||||
{
|
||||
_contextContent.IsOpen = false;
|
||||
}
|
||||
else if (ContextMenu != null)
|
||||
{
|
||||
ContextMenu.IsOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,6 +115,7 @@
|
||||
<Compile Include="Controls\Other\ChatBubble.cs" />
|
||||
<Compile Include="Controls\Other\Dialog.cs" />
|
||||
<Compile Include="Controls\Other\GotoTop.cs" />
|
||||
<Compile Include="Controls\Other\NotifyIcon.cs" />
|
||||
<Compile Include="Controls\Other\Gravatar.cs" />
|
||||
<Compile Include="Controls\Panel\SimplePanel.cs" />
|
||||
<Compile Include="Controls\ProgressBar\WaveProgressBar.cs" />
|
||||
@@ -179,6 +180,8 @@
|
||||
<Compile Include="Data\MessageBoxInfo.cs" />
|
||||
<Compile Include="Data\ResourceToken.cs" />
|
||||
<Compile Include="Data\SystemVersionInfo.cs" />
|
||||
<Compile Include="Interactivity\PushMainWindow2TopCommand.cs" />
|
||||
<Compile Include="Interactivity\ShutdownAppCommand.cs" />
|
||||
<Compile Include="Tools\Converter\Boolean2StrConverter.cs" />
|
||||
<Compile Include="Tools\Converter\BorderClipConverter.cs" />
|
||||
<Compile Include="Tools\Converter\BorderCircularConverter.cs" />
|
||||
@@ -223,8 +226,12 @@
|
||||
<Compile Include="Expression\Media\UnitType.cs" />
|
||||
<Compile Include="Expression\Shapes\Arc.cs" />
|
||||
<Compile Include="Expression\Shapes\PrimitiveShape.cs" />
|
||||
<Compile Include="Tools\Helper\CreateParams.cs" />
|
||||
<Compile Include="Tools\Helper\DesignerHelper.cs" />
|
||||
<Compile Include="Tools\Helper\ExternDllHelper.cs" />
|
||||
<Compile Include="Tools\Helper\IconHelper.cs" />
|
||||
<Compile Include="Tools\Interop\NOTIFYICONDATA.cs" />
|
||||
<Compile Include="Tools\Helper\SecurityHelper.cs" />
|
||||
<Compile Include="Tools\Helper\SingleOpenHelper.cs" />
|
||||
<Compile Include="Controls\TabControl\TabControl.cs" />
|
||||
<Compile Include="Controls\TabControl\TabItem.cs" />
|
||||
@@ -304,6 +311,19 @@
|
||||
<Compile Include="Tools\Converter\TreeViewItemMarginConverter.cs" />
|
||||
<Compile Include="Tools\Extension\ColorExtension.cs" />
|
||||
<Compile Include="Tools\Extension\UIElementExtension.cs" />
|
||||
<Compile Include="Tools\Interop\BitmapHandle.cs" />
|
||||
<Compile Include="Tools\Interop\BITMAPINFO.cs" />
|
||||
<Compile Include="Tools\Interop\CommonHandles.cs" />
|
||||
<Compile Include="Tools\Interop\ExternDll.cs" />
|
||||
<Compile Include="Tools\Interop\HandleCollector.cs" />
|
||||
<Compile Include="Tools\Interop\IconHandle.cs" />
|
||||
<Compile Include="Tools\Interop\ICONINFO.cs" />
|
||||
<Compile Include="Tools\Interop\NativeMethods.cs" />
|
||||
<Compile Include="Tools\Interop\NativeValues.cs" />
|
||||
<Compile Include="Tools\Interop\SafeFileMappingHandle.cs" />
|
||||
<Compile Include="Tools\Interop\UnsafeNativeMethods.cs" />
|
||||
<Compile Include="Tools\Interop\WNDCLASS.cs" />
|
||||
<Compile Include="Tools\Interop\WpfSafeHandle.cs" />
|
||||
<Compile Include="Tools\MouseDragElementBehaviorEx.cs" />
|
||||
<Compile Include="Tools\StyleSelector\RadioGroupItemStyleSelector.cs" />
|
||||
<Compile Include="Tools\RegularJudgment.cs" />
|
||||
|
||||
@@ -146,5 +146,15 @@ namespace HandyControl.Interactivity
|
||||
/// 打开链接
|
||||
/// </summary>
|
||||
public static RoutedCommand OpenLink { get; } = new RoutedCommand(nameof(OpenLink), typeof(ControlCommands));
|
||||
|
||||
/// <summary>
|
||||
/// 关闭程序
|
||||
/// </summary>
|
||||
public static ShutdownAppCommand ShutdownApp { get; } = new ShutdownAppCommand();
|
||||
|
||||
/// <summary>
|
||||
/// 前置主窗口
|
||||
/// </summary>
|
||||
public static PushMainWindow2TopCommand PushMainWindow2Top { get; } = new PushMainWindow2TopCommand();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*refrence from https://github.com/lbugnion/mvvmlight*/
|
||||
// reference from https://github.com/lbugnion/mvvmlight
|
||||
|
||||
//The MIT License(MIT)
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Interactivity
|
||||
{
|
||||
public class PushMainWindow2TopCommand : ICommand
|
||||
{
|
||||
public bool CanExecute(object parameter) => true;
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
if (Application.Current.MainWindow != null && Application.Current.MainWindow.Visibility != Visibility.Visible)
|
||||
{
|
||||
Application.Current.MainWindow.Show();
|
||||
var hwndSource = (HwndSource)PresentationSource.FromDependencyObject(Application.Current.MainWindow);
|
||||
if (hwndSource != null)
|
||||
{
|
||||
UnsafeNativeMethods.SetForegroundWindow(hwndSource.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace HandyControl.Interactivity
|
||||
{
|
||||
public class ShutdownAppCommand : ICommand
|
||||
{
|
||||
public bool CanExecute(object parameter) => true;
|
||||
|
||||
public void Execute(object parameter) => Application.Current.Shutdown();
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
@@ -123,22 +123,22 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Height="22" Width="36" x:Name="backBorder" Background="{DynamicResource BorderBrush}" CornerRadius="11"/>
|
||||
<Border Grid.Column="0" Height="22" Width="36" Opacity="0" x:Name="lightBorder" Background="{DynamicResource PrimaryBrush}" CornerRadius="11" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
|
||||
<Border Grid.Column="0" Margin="1" Background="{TemplateBinding Background}" CornerRadius="11" Name="innerBorder" RenderTransformOrigin=".8,0.5">
|
||||
<Border Grid.Column="0" Height="20" Margin="1" Background="{TemplateBinding Background}" CornerRadius="11" Name="innerBorder" RenderTransformOrigin=".8,0.5">
|
||||
<Border.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
</TransformGroup>
|
||||
</Border.RenderTransform>
|
||||
</Border>
|
||||
<Canvas Grid.Column="0" Margin="1">
|
||||
<Border CornerRadius="10" Name="thumb" Effect="{StaticResource EffectShadow2}" Background="White" Width="20" Height="20" RenderTransformOrigin="0.5,0.5">
|
||||
<controls:SimplePanel Grid.Column="0" Margin="1">
|
||||
<Border HorizontalAlignment="Left" CornerRadius="10" Name="thumb" Effect="{StaticResource EffectShadow2}" Background="White" Width="20" Height="20" RenderTransformOrigin="0.5,0.5">
|
||||
<Border.RenderTransform>
|
||||
<TransformGroup>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Border.RenderTransform>
|
||||
</Border>
|
||||
</Canvas>
|
||||
</controls:SimplePanel>
|
||||
<ContentPresenter x:Name="contentPresenter" Visibility="Collapsed" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal class CreateParams
|
||||
{
|
||||
public string ClassName { get; set; }
|
||||
|
||||
public string Caption { get; set; }
|
||||
|
||||
public int Style { get; set; }
|
||||
|
||||
public int ExStyle{ get; set; }
|
||||
|
||||
public int ClassStyle { get; set; }
|
||||
|
||||
public int X { get; set; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
public IntPtr Parent { get; set; }
|
||||
|
||||
public object Param { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder(64);
|
||||
sb.Append("CreateParams {'");
|
||||
sb.Append(ClassName);
|
||||
sb.Append("', '");
|
||||
sb.Append(Caption);
|
||||
sb.Append("', 0x");
|
||||
sb.Append(Convert.ToString(Style, 16));
|
||||
sb.Append(", 0x");
|
||||
sb.Append(Convert.ToString(ExStyle, 16));
|
||||
sb.Append(", {");
|
||||
sb.Append(X);
|
||||
sb.Append(", ");
|
||||
sb.Append(Y);
|
||||
sb.Append(", ");
|
||||
sb.Append(Width);
|
||||
sb.Append(", ");
|
||||
sb.Append(Height);
|
||||
sb.Append("}");
|
||||
sb.Append("}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,13 @@ using System.Threading;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal class ExternDllHelper
|
||||
{
|
||||
private const string Gdi32 = "gdi32.dll";
|
||||
|
||||
private const string User32 = "user32.dll";
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public const int E_FAIL = unchecked((int) 0x80004005);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
@@ -70,7 +70,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int len);
|
||||
|
||||
|
||||
int Write(
|
||||
[In]
|
||||
IntPtr buf,
|
||||
@@ -84,7 +83,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int dwOrigin);
|
||||
|
||||
|
||||
void SetSize(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libNewSize);
|
||||
@@ -98,15 +96,12 @@ namespace HandyControl.Tools
|
||||
[Out, MarshalAs(UnmanagedType.LPArray)]
|
||||
long[] pcbRead);
|
||||
|
||||
|
||||
void Commit(
|
||||
[In]
|
||||
int grfCommitFlags);
|
||||
|
||||
|
||||
void Revert();
|
||||
|
||||
|
||||
void LockRegion(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libOffset,
|
||||
@@ -115,7 +110,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int dwLockType);
|
||||
|
||||
|
||||
void UnlockRegion(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libOffset,
|
||||
@@ -124,7 +118,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int dwLockType);
|
||||
|
||||
|
||||
void Stat(
|
||||
[In]
|
||||
IntPtr pStatstg,
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal static class IconHelper
|
||||
{
|
||||
private static Size SmallIconSize;
|
||||
|
||||
private static Size IconSize;
|
||||
|
||||
private static int SystemBitDepth;
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
public static void GetIconHandlesFromImageSource(ImageSource image, out IconHandle largeIconHandle, out IconHandle smallIconHandle)
|
||||
{
|
||||
EnsureSystemMetrics();
|
||||
largeIconHandle = CreateIconHandleFromImageSource(image, IconSize);
|
||||
smallIconHandle = CreateIconHandleFromImageSource(image, SmallIconSize);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static IconHandle CreateIconHandleFromImageSource(ImageSource image, Size size)
|
||||
{
|
||||
EnsureSystemMetrics();
|
||||
|
||||
var asGoodAsItGets = false;
|
||||
|
||||
var bf = image as BitmapFrame;
|
||||
if (bf?.Decoder?.Frames != null)
|
||||
{
|
||||
bf = GetBestMatch(bf.Decoder.Frames, size);
|
||||
|
||||
asGoodAsItGets = bf.Decoder is IconBitmapDecoder || bf.PixelWidth == (int)size.Width && bf.PixelHeight == (int)size.Height;
|
||||
|
||||
image = bf;
|
||||
}
|
||||
|
||||
if (!asGoodAsItGets)
|
||||
{
|
||||
bf = BitmapFrame.Create(GenerateBitmapSource(image, size));
|
||||
}
|
||||
|
||||
return CreateIconHandleFromBitmapFrame(bf);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private static IconHandle CreateIconHandleFromBitmapFrame(BitmapFrame sourceBitmapFrame)
|
||||
{
|
||||
BitmapSource bitmapSource = sourceBitmapFrame;
|
||||
|
||||
if (bitmapSource.Format != PixelFormats.Bgra32 && bitmapSource.Format != PixelFormats.Pbgra32)
|
||||
{
|
||||
bitmapSource = new FormatConvertedBitmap(bitmapSource, PixelFormats.Bgra32, null, 0.0);
|
||||
}
|
||||
|
||||
var w = bitmapSource.PixelWidth;
|
||||
var h = bitmapSource.PixelHeight;
|
||||
var bpp = bitmapSource.Format.BitsPerPixel;
|
||||
var stride = (bpp * w + 31) / 32 * 4;
|
||||
var sizeCopyPixels = stride * h;
|
||||
var xor = new byte[sizeCopyPixels];
|
||||
bitmapSource.CopyPixels(xor, stride, 0);
|
||||
|
||||
return CreateIconCursor(xor, w, h, 0, 0, true);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal static IconHandle CreateIconCursor(byte[] colorArray, int width, int height, int xHotspot, int yHotspot, bool isIcon)
|
||||
{
|
||||
BitmapHandle colorBitmap = null;
|
||||
BitmapHandle maskBitmap = null;
|
||||
|
||||
try
|
||||
{
|
||||
var bi = new BITMAPINFO(width, -height, 32)
|
||||
{
|
||||
bmiHeader_biCompression = NativeMethods.BI_RGB
|
||||
};
|
||||
|
||||
var bits = IntPtr.Zero;
|
||||
colorBitmap = UnsafeNativeMethods.CreateDIBSection(new HandleRef(null, IntPtr.Zero), ref bi, NativeMethods.DIB_RGB_COLORS, ref bits, null, 0);
|
||||
|
||||
if (colorBitmap.IsInvalid || bits == IntPtr.Zero)
|
||||
{
|
||||
return IconHandle.GetInvalidIcon();
|
||||
}
|
||||
|
||||
Marshal.Copy(colorArray, 0, bits, colorArray.Length);
|
||||
var maskArray = GenerateMaskArray(width, height, colorArray);
|
||||
|
||||
maskBitmap = UnsafeNativeMethods.CreateBitmap(width, height, 1, 1, maskArray);
|
||||
if (maskBitmap.IsInvalid)
|
||||
{
|
||||
return IconHandle.GetInvalidIcon();
|
||||
}
|
||||
|
||||
var iconInfo = new ICONINFO
|
||||
{
|
||||
fIcon = isIcon,
|
||||
xHotspot = xHotspot,
|
||||
yHotspot = yHotspot,
|
||||
hbmMask = maskBitmap,
|
||||
hbmColor = colorBitmap
|
||||
};
|
||||
|
||||
return UnsafeNativeMethods.CreateIconIndirect(iconInfo);
|
||||
}
|
||||
finally
|
||||
{
|
||||
colorBitmap?.Dispose();
|
||||
maskBitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
internal static int AlignToBytes(double original, int nBytesCount)
|
||||
{
|
||||
var nBitsCount = 8 << (nBytesCount - 1);
|
||||
return ((int)Math.Ceiling(original) + (nBitsCount - 1)) / nBitsCount * nBitsCount;
|
||||
}
|
||||
|
||||
private static BitmapSource GenerateBitmapSource(ImageSource img, Size renderSize)
|
||||
{
|
||||
var drawingDimensions = new Rect(0, 0, renderSize.Width, renderSize.Height);
|
||||
|
||||
var renderRatio = renderSize.Width / renderSize.Height;
|
||||
var aspectRatio = img.Width / img.Height;
|
||||
|
||||
if (img.Width <= renderSize.Width && img.Height <= renderSize.Height)
|
||||
{
|
||||
drawingDimensions = new Rect((renderSize.Width - img.Width) / 2, (renderSize.Height - img.Height) / 2, img.Width, img.Height);
|
||||
}
|
||||
else if (renderRatio > aspectRatio)
|
||||
{
|
||||
var scaledRenderWidth = (img.Width / img.Height) * renderSize.Width;
|
||||
drawingDimensions = new Rect((renderSize.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, renderSize.Height);
|
||||
}
|
||||
else if (renderRatio < aspectRatio)
|
||||
{
|
||||
var scaledRenderHeight = img.Height / img.Width * renderSize.Height;
|
||||
drawingDimensions = new Rect(0, (renderSize.Height - scaledRenderHeight) / 2, renderSize.Width, scaledRenderHeight);
|
||||
}
|
||||
|
||||
var dv = new DrawingVisual();
|
||||
var dc = dv.RenderOpen();
|
||||
dc.DrawImage(img, drawingDimensions);
|
||||
dc.Close();
|
||||
|
||||
var bmp = new RenderTargetBitmap((int)renderSize.Width, (int)renderSize.Height, 96, 96, PixelFormats.Pbgra32);
|
||||
bmp.Render(dv);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private static BitmapFrame GetBestMatch(ReadOnlyCollection<BitmapFrame> frames, Size size)
|
||||
{
|
||||
var bestScore = int.MaxValue;
|
||||
var bestBpp = 0;
|
||||
var bestIndex = 0;
|
||||
|
||||
var isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder;
|
||||
|
||||
for (int i = 0; i < frames.Count && bestScore != 0; ++i)
|
||||
{
|
||||
var currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel;
|
||||
|
||||
if (currentIconBitDepth == 0)
|
||||
{
|
||||
currentIconBitDepth = 8;
|
||||
}
|
||||
|
||||
var score = MatchImage(frames[i], size, currentIconBitDepth);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
bestScore = score;
|
||||
}
|
||||
else if (score == bestScore)
|
||||
{
|
||||
if (bestBpp < currentIconBitDepth)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frames[bestIndex];
|
||||
}
|
||||
|
||||
private static int MatchImage(BitmapFrame frame, Size size, int bpp)
|
||||
{
|
||||
var score = 2 * MyAbs(bpp, SystemBitDepth, false) +
|
||||
MyAbs(frame.PixelWidth, (int)size.Width, true) +
|
||||
MyAbs(frame.PixelHeight, (int)size.Height, true);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private static int MyAbs(int valueHave, int valueWant, bool fPunish)
|
||||
{
|
||||
var diff = (valueHave - valueWant);
|
||||
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = (fPunish ? -2 : -1) * diff;
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
private static void EnsureSystemMetrics()
|
||||
{
|
||||
if (SystemBitDepth == 0)
|
||||
{
|
||||
var hdcDesktop = new HandleRef(null, UnsafeNativeMethods.GetDC(new HandleRef()));
|
||||
try
|
||||
{
|
||||
var sysBitDepth = UnsafeNativeMethods.GetDeviceCaps(hdcDesktop, NativeMethods.BITSPIXEL);
|
||||
sysBitDepth *= UnsafeNativeMethods.GetDeviceCaps(hdcDesktop, NativeMethods.PLANES);
|
||||
|
||||
if (sysBitDepth == 8)
|
||||
{
|
||||
sysBitDepth = 4;
|
||||
}
|
||||
|
||||
var cxSmallIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CXSMICON);
|
||||
var cySmallIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CYSMICON);
|
||||
var cxIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CXICON);
|
||||
var cyIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CYICON);
|
||||
|
||||
SmallIconSize = new Size(cxSmallIcon, cySmallIcon);
|
||||
IconSize = new Size(cxIcon, cyIcon);
|
||||
SystemBitDepth = sysBitDepth;
|
||||
}
|
||||
finally
|
||||
{
|
||||
UnsafeNativeMethods.ReleaseDC(new HandleRef(), hdcDesktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
public static void GetDefaultIconHandles(out IconHandle largeIconHandle, out IconHandle smallIconHandle)
|
||||
{
|
||||
largeIconHandle = null;
|
||||
smallIconHandle = null;
|
||||
|
||||
SecurityHelper.DemandUIWindowPermission();
|
||||
|
||||
var iconModuleFile = UnsafeNativeMethods.GetModuleFileName(new HandleRef());
|
||||
UnsafeNativeMethods.ExtractIconEx(iconModuleFile, 0, out largeIconHandle, out smallIconHandle, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal class SecurityHelper
|
||||
{
|
||||
private static UIPermission _allWindowsUIPermission;
|
||||
|
||||
[SecurityCritical]
|
||||
internal static void DemandUIWindowPermission()
|
||||
{
|
||||
if (_allWindowsUIPermission == null)
|
||||
{
|
||||
_allWindowsUIPermission = new UIPermission(UIPermissionWindow.AllWindows);
|
||||
}
|
||||
_allWindowsUIPermission.Demand();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal struct BITMAPINFO
|
||||
{
|
||||
public int bmiHeader_biSize;
|
||||
|
||||
public int bmiHeader_biWidth;
|
||||
|
||||
public int bmiHeader_biHeight;
|
||||
|
||||
public short bmiHeader_biPlanes;
|
||||
|
||||
public short bmiHeader_biBitCount;
|
||||
|
||||
public int bmiHeader_biCompression;
|
||||
|
||||
public int bmiHeader_biSizeImage;
|
||||
|
||||
public int bmiHeader_biXPelsPerMeter;
|
||||
|
||||
public int bmiHeader_biYPelsPerMeter;
|
||||
|
||||
public int bmiHeader_biClrUsed;
|
||||
|
||||
public int bmiHeader_biClrImportant;
|
||||
|
||||
public BITMAPINFO(int width, int height, short bpp)
|
||||
{
|
||||
bmiHeader_biSize = SizeOf();
|
||||
bmiHeader_biWidth = width;
|
||||
bmiHeader_biHeight = height;
|
||||
bmiHeader_biPlanes = 1;
|
||||
bmiHeader_biBitCount = bpp;
|
||||
bmiHeader_biCompression = 0;
|
||||
bmiHeader_biSizeImage = 0;
|
||||
bmiHeader_biXPelsPerMeter = 0;
|
||||
bmiHeader_biYPelsPerMeter = 0;
|
||||
bmiHeader_biClrUsed = 0;
|
||||
bmiHeader_biClrImportant = 0;
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
private static int SizeOf()
|
||||
{
|
||||
return Marshal.SizeOf(typeof(BITMAPINFO));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return UnsafeNativeMethods.DeleteObject(handle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal HandleRef MakeHandleRef(object obj)
|
||||
{
|
||||
return new HandleRef(obj, handle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal static BitmapHandle CreateFromHandle(IntPtr hbitmap, bool ownsHandle = true)
|
||||
{
|
||||
return new BitmapHandle(ownsHandle)
|
||||
{
|
||||
handle = hbitmap,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal static class CommonHandles
|
||||
{
|
||||
public static readonly int Icon = HandleCollector.RegisterType(nameof(Icon), 20, 500);
|
||||
|
||||
public static readonly int HDC = HandleCollector.RegisterType(nameof(HDC), 100, 2);
|
||||
|
||||
public static readonly int GDI = HandleCollector.RegisterType(nameof(GDI), 50, 500);
|
||||
|
||||
public static readonly int Kernel = HandleCollector.RegisterType(nameof(Kernel), 0, 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal static class ExternDll
|
||||
{
|
||||
public const string
|
||||
User32 = "user32.dll",
|
||||
Gdi32 = "gdi32.dll",
|
||||
Kernel32 = "kernel32.dll",
|
||||
Shell32 = "shell32.dll";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// reference from https://referencesource.microsoft.com/#WindowsBase/Shared/MS/Win32/HandleCollector.cs,d0f99220d8e1b708
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal static class HandleCollector
|
||||
{
|
||||
private static HandleType[] HandleTypes;
|
||||
private static int HandleTypeCount;
|
||||
|
||||
private static readonly object HandleMutex = new object();
|
||||
|
||||
internal static IntPtr Add(IntPtr handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Add();
|
||||
return handle;
|
||||
}
|
||||
|
||||
[System.Security.SecuritySafeCritical]
|
||||
internal static SafeHandle Add(SafeHandle handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Add();
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal static void Add(int type)
|
||||
{
|
||||
HandleTypes[type - 1].Add();
|
||||
}
|
||||
|
||||
internal static int RegisterType(string typeName, int expense, int initialThreshold)
|
||||
{
|
||||
lock (HandleMutex)
|
||||
{
|
||||
if (HandleTypeCount == 0 || HandleTypeCount == HandleTypes.Length)
|
||||
{
|
||||
HandleType[] newTypes = new HandleType[HandleTypeCount + 10];
|
||||
if (HandleTypes != null)
|
||||
{
|
||||
Array.Copy(HandleTypes, 0, newTypes, 0, HandleTypeCount);
|
||||
}
|
||||
HandleTypes = newTypes;
|
||||
}
|
||||
|
||||
HandleTypes[HandleTypeCount++] = new HandleType(expense, initialThreshold);
|
||||
return HandleTypeCount;
|
||||
}
|
||||
}
|
||||
|
||||
internal static IntPtr Remove(IntPtr handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Remove();
|
||||
return handle;
|
||||
}
|
||||
|
||||
[System.Security.SecuritySafeCritical]
|
||||
internal static SafeHandle Remove(SafeHandle handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Remove();
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal static void Remove(int type)
|
||||
{
|
||||
HandleTypes[type - 1].Remove();
|
||||
}
|
||||
|
||||
private class HandleType
|
||||
{
|
||||
private readonly int _initialThreshHold;
|
||||
private int _threshHold;
|
||||
private int _handleCount;
|
||||
private readonly int _deltaPercent;
|
||||
|
||||
internal HandleType(int expense, int initialThreshHold)
|
||||
{
|
||||
_initialThreshHold = initialThreshHold;
|
||||
_threshHold = initialThreshHold;
|
||||
_deltaPercent = 100 - expense;
|
||||
}
|
||||
|
||||
internal void Add()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
_handleCount++;
|
||||
var performCollect = NeedCollection();
|
||||
|
||||
if (!performCollect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GC.Collect();
|
||||
|
||||
var sleep = (100 - _deltaPercent) / 4;
|
||||
System.Threading.Thread.Sleep(sleep);
|
||||
}
|
||||
|
||||
private bool NeedCollection()
|
||||
{
|
||||
|
||||
if (_handleCount > _threshHold)
|
||||
{
|
||||
_threshHold = _handleCount + _handleCount * _deltaPercent / 100;
|
||||
return true;
|
||||
}
|
||||
|
||||
var oldThreshHold = 100 * _threshHold / (100 + _deltaPercent);
|
||||
if (oldThreshHold >= _initialThreshHold && _handleCount < (int)(oldThreshHold * .9F))
|
||||
{
|
||||
_threshHold = oldThreshHold;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void Remove()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
_handleCount--;
|
||||
|
||||
_handleCount = Math.Max(0, _handleCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal class ICONINFO
|
||||
{
|
||||
public bool fIcon = false;
|
||||
public int xHotspot = 0;
|
||||
public int yHotspot = 0;
|
||||
public BitmapHandle hbmMask = null;
|
||||
public BitmapHandle hbmColor = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Security;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal sealed class IconHandle : WpfSafeHandle
|
||||
{
|
||||
[SecurityCritical]
|
||||
private IconHandle() : base(true, CommonHandles.Icon)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return UnsafeNativeMethods.DestroyIcon(handle);
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
internal static IconHandle GetInvalidIcon()
|
||||
{
|
||||
return new IconHandle();
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal IntPtr CriticalGetHandle()
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class NOTIFYICONDATA
|
||||
{
|
||||
public int cbSize = Marshal.SizeOf(typeof(NOTIFYICONDATA));
|
||||
public IntPtr hWnd;
|
||||
public int uID;
|
||||
public int uFlags;
|
||||
public int uCallbackMessage;
|
||||
public IntPtr hIcon;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||
public string szTip = string.Empty;
|
||||
public int dwState = 0x01;
|
||||
public int dwStateMask = 0x01;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
public string szInfo = string.Empty;
|
||||
public int uTimeoutOrVersion;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
|
||||
public string szInfoTitle = string.Empty;
|
||||
public int dwInfoFlags;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "IdentifierTypo")]
|
||||
internal class NativeMethods
|
||||
{
|
||||
public const int
|
||||
WS_CHILD = 0x40000000,
|
||||
BITSPIXEL = 12,
|
||||
PLANES = 14,
|
||||
BI_RGB = 0,
|
||||
DIB_RGB_COLORS = 0,
|
||||
NIF_MESSAGE = 0x00000001,
|
||||
NIF_ICON = 0x00000002,
|
||||
NIF_TIP = 0x00000004,
|
||||
NIF_INFO = 0x00000010,
|
||||
NIN_BALLOONSHOW = WM_USER + 2,
|
||||
NIN_BALLOONHIDE = WM_USER + 3,
|
||||
NIN_BALLOONTIMEOUT = WM_USER + 4,
|
||||
NIM_ADD = 0x00000000,
|
||||
NIM_MODIFY = 0x00000001,
|
||||
NIM_DELETE = 0x00000002,
|
||||
NIIF_NONE = 0x00000000,
|
||||
NIIF_INFO = 0x00000001,
|
||||
NIIF_WARNING = 0x00000002,
|
||||
NIIF_ERROR = 0x00000003,
|
||||
WM_MOUSEMOVE = 0x0200,
|
||||
WM_LBUTTONDOWN = 0x0201,
|
||||
WM_LBUTTONUP = 0x0202,
|
||||
WM_LBUTTONDBLCLK = 0x0203,
|
||||
WM_RBUTTONDOWN = 0x0204,
|
||||
WM_RBUTTONUP = 0x0205,
|
||||
WM_RBUTTONDBLCLK = 0x0206,
|
||||
WM_MBUTTONDOWN = 0x0207,
|
||||
WM_MBUTTONUP = 0x0208,
|
||||
WM_MBUTTONDBLCLK = 0x0209,
|
||||
WM_USER = 0x0400;
|
||||
|
||||
[DllImport(ExternDll.User32, CharSet = CharSet.Auto)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
public static extern int RegisterWindowMessage(string msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal enum SM
|
||||
{
|
||||
CXSCREEN = 0,
|
||||
CYSCREEN = 1,
|
||||
CXVSCROLL = 2,
|
||||
CYHSCROLL = 3,
|
||||
CYCAPTION = 4,
|
||||
CXBORDER = 5,
|
||||
CYBORDER = 6,
|
||||
CXFIXEDFRAME = 7,
|
||||
CYFIXEDFRAME = 8,
|
||||
CYVTHUMB = 9,
|
||||
CXHTHUMB = 10,
|
||||
CXICON = 11,
|
||||
CYICON = 12,
|
||||
CXCURSOR = 13,
|
||||
CYCURSOR = 14,
|
||||
CYMENU = 15,
|
||||
CXFULLSCREEN = 16,
|
||||
CYFULLSCREEN = 17,
|
||||
CYKANJIWINDOW = 18,
|
||||
MOUSEPRESENT = 19,
|
||||
CYVSCROLL = 20,
|
||||
CXHSCROLL = 21,
|
||||
DEBUG = 22,
|
||||
SWAPBUTTON = 23,
|
||||
CXMIN = 28,
|
||||
CYMIN = 29,
|
||||
CXSIZE = 30,
|
||||
CYSIZE = 31,
|
||||
CXFRAME = 32,
|
||||
CXSIZEFRAME = CXFRAME,
|
||||
CYFRAME = 33,
|
||||
CYSIZEFRAME = CYFRAME,
|
||||
CXMINTRACK = 34,
|
||||
CYMINTRACK = 35,
|
||||
CXDOUBLECLK = 36,
|
||||
CYDOUBLECLK = 37,
|
||||
CXICONSPACING = 38,
|
||||
CYICONSPACING = 39,
|
||||
MENUDROPALIGNMENT = 40,
|
||||
PENWINDOWS = 41,
|
||||
DBCSENABLED = 42,
|
||||
CMOUSEBUTTONS = 43,
|
||||
SECURE = 44,
|
||||
CXEDGE = 45,
|
||||
CYEDGE = 46,
|
||||
CXMINSPACING = 47,
|
||||
CYMINSPACING = 48,
|
||||
CXSMICON = 49,
|
||||
CYSMICON = 50,
|
||||
CYSMCAPTION = 51,
|
||||
CXSMSIZE = 52,
|
||||
CYSMSIZE = 53,
|
||||
CXMENUSIZE = 54,
|
||||
CYMENUSIZE = 55,
|
||||
ARRANGE = 56,
|
||||
CXMINIMIZED = 57,
|
||||
CYMINIMIZED = 58,
|
||||
CXMAXTRACK = 59,
|
||||
CYMAXTRACK = 60,
|
||||
CXMAXIMIZED = 61,
|
||||
CYMAXIMIZED = 62,
|
||||
NETWORK = 63,
|
||||
CLEANBOOT = 67,
|
||||
CXDRAG = 68,
|
||||
CYDRAG = 69,
|
||||
SHOWSOUNDS = 70,
|
||||
CXMENUCHECK = 71,
|
||||
CYMENUCHECK = 72,
|
||||
SLOWMACHINE = 73,
|
||||
MIDEASTENABLED = 74,
|
||||
MOUSEWHEELPRESENT = 75,
|
||||
XVIRTUALSCREEN = 76,
|
||||
YVIRTUALSCREEN = 77,
|
||||
CXVIRTUALSCREEN = 78,
|
||||
CYVIRTUALSCREEN = 79,
|
||||
CMONITORS = 80,
|
||||
SAMEDISPLAYFORMAT = 81,
|
||||
IMMENABLED = 82,
|
||||
CXFOCUSBORDER = 83,
|
||||
CYFOCUSBORDER = 84,
|
||||
TABLETPC = 86,
|
||||
MEDIACENTER = 87,
|
||||
REMOTESESSION = 0x1000,
|
||||
REMOTECONTROL = 0x2001,
|
||||
}
|
||||
|
||||
internal static class Win32Constant
|
||||
{
|
||||
internal const int MAX_PATH = 260;
|
||||
internal const int INFOTIPSIZE = 1024;
|
||||
internal const int TRUE = 1;
|
||||
internal const int FALSE = 0;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class POINT
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
public POINT()
|
||||
{
|
||||
}
|
||||
|
||||
public POINT(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal sealed class SafeFileMappingHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[SecurityCritical]
|
||||
internal SafeFileMappingHandle(IntPtr handle) : base(false)
|
||||
{
|
||||
SetHandle(handle);
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
internal SafeFileMappingHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
get => handle == IntPtr.Zero;
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
|
||||
try
|
||||
{
|
||||
return CloseHandleNoThrow(new HandleRef(null, handle));
|
||||
}
|
||||
finally
|
||||
{
|
||||
CodeAccessPermission.RevertAssert();
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static bool CloseHandleNoThrow(HandleRef handle)
|
||||
{
|
||||
HandleCollector.Remove((IntPtr)handle, CommonHandles.Kernel);
|
||||
var result = UnsafeNativeMethods.IntCloseHandle(handle);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal class UnsafeNativeMethods
|
||||
{
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, EntryPoint = nameof(GetDC), CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr IntGetDC(HandleRef hWnd);
|
||||
|
||||
[SecurityCritical]
|
||||
public static IntPtr GetDC(HandleRef hWnd)
|
||||
{
|
||||
var hDc = IntGetDC(hWnd);
|
||||
if (hDc == IntPtr.Zero)
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
return HandleCollector.Add(hDc, CommonHandles.HDC);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, ExactSpelling = true, EntryPoint = nameof(ReleaseDC), CharSet = CharSet.Auto)]
|
||||
public static extern int IntReleaseDC(HandleRef hWnd, HandleRef hDC);
|
||||
|
||||
[SecurityCritical]
|
||||
public static int ReleaseDC(HandleRef hWnd, HandleRef hDC)
|
||||
{
|
||||
HandleCollector.Remove((IntPtr)hDC, CommonHandles.HDC);
|
||||
return IntReleaseDC(hWnd, hDC);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
|
||||
public static extern int GetDeviceCaps(HandleRef hDC, int nIndex);
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32)]
|
||||
public static extern int GetSystemMetrics(SM nIndex);
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, EntryPoint = nameof(DestroyIcon), CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool IntDestroyIcon(IntPtr hIcon);
|
||||
|
||||
[SecurityCritical]
|
||||
public static bool DestroyIcon(IntPtr hIcon)
|
||||
{
|
||||
var result = IntDestroyIcon(hIcon);
|
||||
return result;
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, EntryPoint = nameof(DeleteObject), CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool IntDeleteObject(IntPtr hObject);
|
||||
|
||||
[SecurityCritical]
|
||||
public static bool DeleteObject(IntPtr hObject)
|
||||
{
|
||||
var result = IntDeleteObject(hObject);
|
||||
return result;
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static BitmapHandle CreateDIBSection(HandleRef hdc, ref BITMAPINFO bitmapInfo, int iUsage, ref IntPtr ppvBits, SafeFileMappingHandle hSection, int dwOffset)
|
||||
{
|
||||
if (hSection == null)
|
||||
{
|
||||
hSection = new SafeFileMappingHandle(IntPtr.Zero);
|
||||
}
|
||||
|
||||
var hBitmap = PrivateCreateDIBSection(hdc, ref bitmapInfo, iUsage, ref ppvBits, hSection, dwOffset);
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
[DllImport(ExternDll.Kernel32, EntryPoint = "CloseHandle", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern bool IntCloseHandle(HandleRef handle);
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = nameof(CreateDIBSection))]
|
||||
private static extern BitmapHandle PrivateCreateDIBSection(HandleRef hdc, ref BITMAPINFO bitmapInfo, int iUsage, ref IntPtr ppvBits, SafeFileMappingHandle hSection, int dwOffset);
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = nameof(CreateIconIndirect))]
|
||||
private static extern IconHandle PrivateCreateIconIndirect([In, MarshalAs(UnmanagedType.LPStruct)]ICONINFO iconInfo);
|
||||
|
||||
[SecurityCritical]
|
||||
public static IconHandle CreateIconIndirect([In, MarshalAs(UnmanagedType.LPStruct)]ICONINFO iconInfo)
|
||||
{
|
||||
var hIcon = PrivateCreateIconIndirect(iconInfo);
|
||||
return hIcon;
|
||||
}
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = nameof(CreateBitmap))]
|
||||
private static extern BitmapHandle PrivateCreateBitmap(int width, int height, int planes, int bitsPerPixel, byte[] lpvBits);
|
||||
|
||||
[SecurityCritical]
|
||||
internal static BitmapHandle CreateBitmap(int width, int height, int planes, int bitsPerPixel, byte[] lpvBits)
|
||||
{
|
||||
var hBitmap = PrivateCreateBitmap(width, height, planes, bitsPerPixel, lpvBits);
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Kernel32, EntryPoint = "GetModuleFileName", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern int IntGetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
|
||||
|
||||
[SecurityCritical]
|
||||
internal static string GetModuleFileName(HandleRef hModule)
|
||||
{
|
||||
var buffer = new StringBuilder(Win32Constant.MAX_PATH);
|
||||
while (true)
|
||||
{
|
||||
var size = IntGetModuleFileName(hModule, buffer, buffer.Capacity);
|
||||
if (size == 0)
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
if (size == buffer.Capacity)
|
||||
{
|
||||
buffer.EnsureCapacity(buffer.Capacity * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Shell32, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
internal static extern int ExtractIconEx(string szExeFileName, int nIconIndex, out IconHandle phiconLarge, out IconHandle phiconSmall, int nIcons);
|
||||
|
||||
[DllImport(ExternDll.Shell32, CharSet = CharSet.Auto)]
|
||||
public static extern int Shell_NotifyIcon(int message, NOTIFYICONDATA pnid);
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
[DllImport(ExternDll.User32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateWindowExW")]
|
||||
public static extern IntPtr CreateWindowEx(
|
||||
int dwExStyle,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpClassName,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpWindowName,
|
||||
int dwStyle,
|
||||
int x,
|
||||
int y,
|
||||
int nWidth,
|
||||
int nHeight,
|
||||
IntPtr hWndParent,
|
||||
IntPtr hMenu,
|
||||
IntPtr hInstance,
|
||||
IntPtr lpParam);
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)]
|
||||
public static extern short RegisterClass(WNDCLASS wc);
|
||||
|
||||
[DllImport(ExternDll.User32, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr DefWindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool GetCursorPos([In, Out] POINT pt);
|
||||
|
||||
[DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "IdentifierTypo")]
|
||||
internal class WNDCLASS
|
||||
{
|
||||
public int style;
|
||||
public WndProc lpfnWndProc;
|
||||
public int cbClsExtra;
|
||||
public int cbWndExtra;
|
||||
public IntPtr hInstance;
|
||||
public IntPtr hIcon;
|
||||
public IntPtr hCursor;
|
||||
public IntPtr hbrBackground;
|
||||
public string lpszMenuName;
|
||||
public string lpszClassName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Security;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal abstract class WpfSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private readonly int _collectorId;
|
||||
|
||||
[SecurityCritical]
|
||||
protected WpfSafeHandle(bool ownsHandle, int collectorId) : base(ownsHandle)
|
||||
{
|
||||
HandleCollector.Add(collectorId);
|
||||
_collectorId = collectorId;
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
HandleCollector.Remove(_collectorId);
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,5 +32,7 @@ namespace HandyControlDemo.Data
|
||||
}
|
||||
|
||||
public static AppConfig Config { get; set; }
|
||||
|
||||
public static bool NotifyIconIsShow { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,8 @@
|
||||
|
||||
public static readonly string GotoTopDemoCtl = nameof(GotoTopDemoCtl);
|
||||
|
||||
public static readonly string NotifyIconDemoCtl = nameof(NotifyIconDemoCtl);
|
||||
|
||||
public static readonly string BadgeDemoCtl = nameof(BadgeDemoCtl);
|
||||
|
||||
public static readonly string GravatarDemoCtl = nameof(GravatarDemoCtl);
|
||||
|
||||
@@ -45,6 +45,7 @@ var controlList = new List<string>
|
||||
"TransferDemoCtl",
|
||||
"ChatBubbleDemoCtl",
|
||||
"GotoTopDemoCtl",
|
||||
"NotifyIconDemoCtl"
|
||||
"BadgeDemoCtl",
|
||||
"GravatarDemoCtl",
|
||||
"DialogDemoCtl"
|
||||
|
||||
@@ -187,6 +187,9 @@
|
||||
<Compile Include="UserControl\Controls\GotoTopDemoCtl.xaml.cs">
|
||||
<DependentUpon>GotoTopDemoCtl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserControl\Controls\NotifyIconDemoCtl.xaml.cs">
|
||||
<DependentUpon>NotifyIconDemoCtl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UserControl\Controls\GravatarDemoCtl.xaml.cs">
|
||||
<DependentUpon>GravatarDemoCtl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -359,6 +362,7 @@
|
||||
<Compile Include="ViewModel\Common\ComboBoxDemoViewModel.cs" />
|
||||
<Compile Include="ViewModel\Controls\CoverViewModel.cs" />
|
||||
<Compile Include="ViewModel\Controls\DialogDemoViewModel.cs" />
|
||||
<Compile Include="ViewModel\Controls\NotifyIconDemoViewModel.cs" />
|
||||
<Compile Include="ViewModel\Controls\SearchBarDemoViewModel.cs" />
|
||||
<Compile Include="ViewModel\DemoViewModelBase!1.cs" />
|
||||
<Compile Include="ViewModel\Main\ContributorsViewModel.cs" />
|
||||
@@ -527,6 +531,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UserControl\Controls\NotifyIconDemoCtl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UserControl\Controls\GravatarDemoCtl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -797,6 +805,8 @@
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>MessageToken.cs</LastGenOutput>
|
||||
</Content>
|
||||
<Resource Include="Resources\Img\icon-white.ico" />
|
||||
<Resource Include="Resources\Img\LeftMainContent\NotificationHub_16x.png" />
|
||||
<Resource Include="Resources\Img\LeftMainContent\Dialog_16x.png" />
|
||||
<Resource Include="Resources\Img\under_construction.gif" />
|
||||
<Resource Include="Resources\Img\LeftMainContent\User_16x.png" />
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using HandyControl.Controls;
|
||||
using HandyControlDemo.Data;
|
||||
|
||||
namespace HandyControlDemo
|
||||
{
|
||||
@@ -23,5 +25,19 @@ namespace HandyControlDemo
|
||||
|
||||
Growl.SetGrowlParent(GrowlPanel, false);
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
if (GlobalData.NotifyIconIsShow)
|
||||
{
|
||||
MessageBox.Info(Properties.Langs.Lang.AppClosingTip, Properties.Langs.Lang.Tip);
|
||||
Hide();
|
||||
e.Cancel = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnClosing(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 托盘图标已打开,将隐藏窗口而不是关闭程序 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string AppClosingTip {
|
||||
get {
|
||||
return ResourceManager.GetString("AppClosingTip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 询问 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -105,6 +114,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 闪烁 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Blink {
|
||||
get {
|
||||
return ResourceManager.GetString("Blink", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 博客 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -429,6 +447,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 退出 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Exit {
|
||||
get {
|
||||
return ResourceManager.GetString("Exit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 展开框 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -699,6 +726,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 托盘图标 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string NotifyIcon {
|
||||
get {
|
||||
return ResourceManager.GetString("NotifyIcon", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 数值选择控件 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -789,6 +825,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 打开面板 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string OpenPanel {
|
||||
get {
|
||||
return ResourceManager.GetString("OpenPanel", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 轮廓文本 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1167,6 +1212,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 提示 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Tip {
|
||||
get {
|
||||
return ResourceManager.GetString("Tip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 标题 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1239,6 +1293,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 试试关闭程序吧? 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Try2CloseApp {
|
||||
get {
|
||||
return ResourceManager.GetString("Try2CloseApp", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 类型 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -1266,6 +1329,15 @@ namespace HandyControlDemo.Properties.Langs {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 可见性 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Visibility {
|
||||
get {
|
||||
return ResourceManager.GetString("Visibility", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 警告 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -498,6 +498,9 @@
|
||||
<data name="GotoTop" xml:space="preserve">
|
||||
<value>GotoTop</value>
|
||||
</data>
|
||||
<data name="NotifyIcon" xml:space="preserve">
|
||||
<value>NotifyIcon</value>
|
||||
</data>
|
||||
<data name="Badge" xml:space="preserve">
|
||||
<value>Badge</value>
|
||||
</data>
|
||||
@@ -528,4 +531,25 @@
|
||||
<data name="NewWindow" xml:space="preserve">
|
||||
<value>New window</value>
|
||||
</data>
|
||||
<data name="Visibility" xml:space="preserve">
|
||||
<value>Visibility</value>
|
||||
</data>
|
||||
<data name="Blink" xml:space="preserve">
|
||||
<value>Blink</value>
|
||||
</data>
|
||||
<data name="Exit" xml:space="preserve">
|
||||
<value>Exit</value>
|
||||
</data>
|
||||
<data name="OpenPanel" xml:space="preserve">
|
||||
<value>Open Panel</value>
|
||||
</data>
|
||||
<data name="AppClosingTip" xml:space="preserve">
|
||||
<value>The tray icon is open and will hide the window instead of closing the program</value>
|
||||
</data>
|
||||
<data name="Tip" xml:space="preserve">
|
||||
<value>Prompt</value>
|
||||
</data>
|
||||
<data name="Try2CloseApp" xml:space="preserve">
|
||||
<value>Try to close app?</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -498,6 +498,9 @@
|
||||
<data name="GotoTop" xml:space="preserve">
|
||||
<value>回到顶部</value>
|
||||
</data>
|
||||
<data name="NotifyIcon" xml:space="preserve">
|
||||
<value>托盘图标</value>
|
||||
</data>
|
||||
<data name="Badge" xml:space="preserve">
|
||||
<value>标记</value>
|
||||
</data>
|
||||
@@ -528,4 +531,25 @@
|
||||
<data name="NewWindow" xml:space="preserve">
|
||||
<value>新建窗口</value>
|
||||
</data>
|
||||
<data name="Visibility" xml:space="preserve">
|
||||
<value>可见性</value>
|
||||
</data>
|
||||
<data name="Blink" xml:space="preserve">
|
||||
<value>闪烁</value>
|
||||
</data>
|
||||
<data name="Exit" xml:space="preserve">
|
||||
<value>退出</value>
|
||||
</data>
|
||||
<data name="OpenPanel" xml:space="preserve">
|
||||
<value>打开面板</value>
|
||||
</data>
|
||||
<data name="AppClosingTip" xml:space="preserve">
|
||||
<value>托盘图标已打开,将隐藏窗口而不是关闭程序</value>
|
||||
</data>
|
||||
<data name="Tip" xml:space="preserve">
|
||||
<value>提示</value>
|
||||
</data>
|
||||
<data name="Try2CloseApp" xml:space="preserve">
|
||||
<value>试试关闭程序吧?</value>
|
||||
</data>
|
||||
</root>
|
||||
|
After Width: | Height: | Size: 335 B |
|
After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,76 @@
|
||||
<UserControl x:Class="HandyControlDemo.UserControl.NotifyIconDemoCtl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs"
|
||||
xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"
|
||||
xmlns:interactivity="clr-namespace:HandyControl.Interactivity;assembly=HandyControl"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:command="http://www.galasoft.ch/mvvmlight"
|
||||
DataContext="{Binding NotifyIconDemo,Source={StaticResource Locator}}"
|
||||
Background="{DynamicResource RegionBrush}">
|
||||
<controls:TransitioningContentControl>
|
||||
<controls:SimplePanel Margin="32">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<GroupBox Header="ContextMenu" Padding="10">
|
||||
<StackPanel>
|
||||
<GroupBox controls:TitleElement.TitleAlignment="Left" Style="{StaticResource GroupBoxOriginal}" Header="{x:Static langs:Lang.Visibility}">
|
||||
<ToggleButton IsChecked="{Binding ContextMenuIsShow}" Style="{StaticResource ToggleButtonSwitch}"/>
|
||||
</GroupBox>
|
||||
<TextBlock Foreground="{DynamicResource InfoBrush}" Visibility="{Binding ContextMenuIsShow,Converter={StaticResource Boolean2VisibilityConverter}}" Text="{x:Static langs:Lang.Try2CloseApp}" Margin="0,6,0,0"/>
|
||||
<GroupBox Margin="0,10,0,0" controls:TitleElement.TitleAlignment="Left" Style="{StaticResource GroupBoxOriginal}" Header="{x:Static langs:Lang.Blink}">
|
||||
<ToggleButton IsChecked="{Binding ContextMenuIsBlink}" IsEnabled="{Binding ContextMenuIsShow}" Style="{StaticResource ToggleButtonSwitch}"/>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="ContextContent" Margin="16,0,0,0" Padding="10">
|
||||
<StackPanel>
|
||||
<GroupBox controls:TitleElement.TitleAlignment="Left" Style="{StaticResource GroupBoxOriginal}" Header="{x:Static langs:Lang.Visibility}">
|
||||
<ToggleButton IsChecked="{Binding ContextContentIsShow}" Style="{StaticResource ToggleButtonSwitch}"/>
|
||||
</GroupBox>
|
||||
<TextBlock Foreground="{DynamicResource InfoBrush}" Visibility="{Binding ContextContentIsShow,Converter={StaticResource Boolean2VisibilityConverter}}" Text="{x:Static langs:Lang.Try2CloseApp}" Margin="0,6,0,0"/>
|
||||
<GroupBox Margin="0,10,0,0" controls:TitleElement.TitleAlignment="Left" Style="{StaticResource GroupBoxOriginal}" Header="{x:Static langs:Lang.Blink}">
|
||||
<ToggleButton IsChecked="{Binding ContextContentIsBlink}" IsEnabled="{Binding ContextContentIsShow}" Style="{StaticResource ToggleButtonSwitch}"/>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
<controls:NotifyIcon Text="HandyControl" IsBlink="{Binding ContextMenuIsBlink}" Visibility="{Binding ContextMenuIsShow,Converter={StaticResource Boolean2VisibilityConverter}}">
|
||||
<controls:NotifyIcon.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Command="interactivity:ControlCommands.PushMainWindow2Top" Header="{x:Static langs:Lang.OpenPanel}"/>
|
||||
<MenuItem Command="interactivity:ControlCommands.ShutdownApp" Header="{x:Static langs:Lang.Exit}"/>
|
||||
</ContextMenu>
|
||||
</controls:NotifyIcon.ContextMenu>
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Click">
|
||||
<command:EventToCommand Command="interactivity:ControlCommands.PushMainWindow2Top"/>
|
||||
</i:EventTrigger>
|
||||
<i:EventTrigger EventName="MouseDoubleClick">
|
||||
<command:EventToCommand Command="{Binding MouseCmd}" CommandParameter="MouseDoubleClick"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</controls:NotifyIcon>
|
||||
<controls:NotifyIcon x:Name="NotifyIconContextContent" Text="HandyControl" IsBlink="{Binding ContextContentIsBlink}" Visibility="{Binding ContextContentIsShow,Converter={StaticResource Boolean2VisibilityConverter}}" Icon="/HandyControlDemo;component/Resources/Img/icon-white.ico">
|
||||
<controls:NotifyIcon.ContextContent>
|
||||
<Border CornerRadius="4" Margin="10" Background="White" Effect="{StaticResource EffectShadow2}">
|
||||
<StackPanel VerticalAlignment="Center" Margin="16">
|
||||
<Path Width="100" Height="100" Fill="#f06632" Data="{StaticResource LogoGeometry}"/>
|
||||
<StackPanel Margin="0,16,0,0" HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<Button Click="ButtonPush_OnClick" Command="interactivity:ControlCommands.PushMainWindow2Top" MinWidth="100" Content="{x:Static langs:Lang.OpenPanel}"/>
|
||||
<Button Command="interactivity:ControlCommands.ShutdownApp" Margin="16,0,0,0" MinWidth="100" Style="{StaticResource ButtonPrimary}" Content="{x:Static langs:Lang.Exit}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</controls:NotifyIcon.ContextContent>
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="Click">
|
||||
<command:EventToCommand Command="interactivity:ControlCommands.PushMainWindow2Top"/>
|
||||
</i:EventTrigger>
|
||||
<i:EventTrigger EventName="MouseDoubleClick">
|
||||
<command:EventToCommand Command="{Binding MouseCmd}" CommandParameter="MouseDoubleClick"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</controls:NotifyIcon>
|
||||
</controls:SimplePanel>
|
||||
</controls:TransitioningContentControl>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControlDemo.UserControl
|
||||
{
|
||||
public partial class NotifyIconDemoCtl
|
||||
{
|
||||
public NotifyIconDemoCtl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ButtonPush_OnClick(object sender, RoutedEventArgs e) => NotifyIconContextContent.CloseContextControl();
|
||||
}
|
||||
}
|
||||
@@ -213,6 +213,11 @@
|
||||
<Image Source="../../Resources/Img/LeftMainContent/Bubble_16xLG.png"/>
|
||||
</controls:EdgeElement.LeftContent>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem Style="{StaticResource ListBoxItemNew}" Tag="{x:Static data:MessageToken.NotifyIconDemoCtl}" Content="{x:Static langs:Lang.NotifyIcon}">
|
||||
<controls:EdgeElement.LeftContent>
|
||||
<Image Source="../../Resources/Img/LeftMainContent/NotificationHub_16x.png"/>
|
||||
</controls:EdgeElement.LeftContent>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem Tag="{x:Static data:MessageToken.NumericUpDownDemoCtl}" Content="{x:Static langs:Lang.NumericUpDown}">
|
||||
<controls:EdgeElement.LeftContent>
|
||||
<Image Source="../../Resources/Img/LeftMainContent/NumericListBox_16x.png"/>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -32,7 +31,7 @@ namespace HandyControlDemo.UserControl
|
||||
GlobalData.Config.Lang = tag;
|
||||
GlobalData.Save();
|
||||
Process.Start(Assembly.GetExecutingAssembly().Location);
|
||||
Environment.Exit(0);
|
||||
Application.Current.Shutdown();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using GalaSoft.MvvmLight;
|
||||
using GalaSoft.MvvmLight.CommandWpf;
|
||||
using HandyControl.Controls;
|
||||
using HandyControlDemo.Data;
|
||||
|
||||
namespace HandyControlDemo.ViewModel
|
||||
{
|
||||
public class NotifyIconDemoViewModel : ViewModelBase
|
||||
{
|
||||
private bool _contextMenuIsShow;
|
||||
|
||||
public bool ContextMenuIsShow
|
||||
{
|
||||
get => _contextMenuIsShow;
|
||||
set
|
||||
{
|
||||
Set(ref _contextMenuIsShow, value);
|
||||
GlobalData.NotifyIconIsShow = ContextMenuIsShow || ContextContentIsShow;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _contextMenuIsBlink;
|
||||
|
||||
public bool ContextMenuIsBlink
|
||||
{
|
||||
get => _contextMenuIsBlink;
|
||||
set => Set(ref _contextMenuIsBlink, value);
|
||||
}
|
||||
|
||||
private bool _contextContentIsShow;
|
||||
|
||||
public bool ContextContentIsShow
|
||||
{
|
||||
get => _contextContentIsShow;
|
||||
set
|
||||
{
|
||||
Set(ref _contextContentIsShow, value);
|
||||
GlobalData.NotifyIconIsShow = ContextMenuIsShow || ContextContentIsShow;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _contextContentIsBlink;
|
||||
|
||||
public bool ContextContentIsBlink
|
||||
{
|
||||
get => _contextContentIsBlink;
|
||||
set => Set(ref _contextContentIsBlink, value);
|
||||
}
|
||||
|
||||
public RelayCommand<object> MouseCmd => new Lazy<RelayCommand<object>>(() =>
|
||||
new RelayCommand<object>(str=> Growl.Info(str.ToString()))).Value;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ namespace HandyControlDemo.ViewModel
|
||||
SimpleIoc.Default.Register<CoverViewModel>();
|
||||
SimpleIoc.Default.Register<DialogDemoViewModel>();
|
||||
SimpleIoc.Default.Register<SearchBarDemoViewModel>();
|
||||
SimpleIoc.Default.Register<NotifyIconDemoViewModel>();
|
||||
}
|
||||
|
||||
public static ViewModelLocator Instance => new Lazy<ViewModelLocator>(() =>
|
||||
@@ -57,6 +58,8 @@ namespace HandyControlDemo.ViewModel
|
||||
|
||||
public SearchBarDemoViewModel SearchBarDemo => ServiceLocator.Current.GetInstance<SearchBarDemoViewModel>();
|
||||
|
||||
public NotifyIconDemoViewModel NotifyIconDemo => ServiceLocator.Current.GetInstance<NotifyIconDemoViewModel>();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,9 @@
|
||||
|
||||

|
||||
|
||||
## 捐赠
|
||||
如果您觉得HandyControl还不错,那么就以HandyControl的名义,花一顿饭的钱来为慈善事业做一份贡献吧(捐赠留言写:HandyControl),谢谢大家。
|
||||
## Special thanks to
|
||||
|
||||
捐赠链接:
|
||||
[中华慈善总会](http://www.chinacharityfederation.org/ConfirmDonation/0.html?zhijie=3)
|
||||
|
||||
也可以扫下面的二维码:
|
||||

|
||||
[](https://www.jetbrains.com/?from=HandyControl)
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -39,6 +34,10 @@ Step 3:enjoy coding
|
||||
|
||||
## Latest examples
|
||||
|
||||
### NotifyIcon
|
||||
|
||||

|
||||
|
||||
### Dialog
|
||||
|
||||

|
||||
@@ -55,12 +54,12 @@ Step 3:enjoy coding
|
||||
|
||||

|
||||
|
||||
## History publication
|
||||
|
||||
### ChatBubble
|
||||
|
||||

|
||||
|
||||
## History publication
|
||||
|
||||
### Transfer
|
||||
|
||||

|
||||
@@ -287,6 +286,14 @@ Step 3:enjoy coding
|
||||
|
||||

|
||||
|
||||
# Switching configuration
|
||||
## Switching configuration
|
||||
|
||||

|
||||
|
||||
# 捐赠(面向中国)
|
||||
如果您觉得HandyControl还不错,并且刚好有些闲钱,那么你可以选择以下两种方式来捐赠:
|
||||
|
||||
* [以HandyControl的名义为慈善事业做贡献](http://www.chinacharityfederation.org/ConfirmDonation/0.html?zhijie=3)
|
||||
|
||||
* 为我们购买防脱洗发水
|
||||

|
||||
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="22.9451" y1="75.7869" x2="74.7868" y2="20.6415">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.4044" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.4677" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.6505" style="stop-color:#EB8523"/>
|
||||
<stop offset="0.9516" style="stop-color:#FEBD11"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_1_);" points="49.8,15.2 36,36.7 58.4,70 70,23.1 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="17.7187" y1="73.2922" x2="69.5556" y2="18.1519">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.4044" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.4677" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.7043" style="stop-color:#EB8523"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_2_);" points="51.1,15.7 49,0 18.8,33.6 27.6,42.3 20.8,70 58.4,70 "/>
|
||||
</g>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1.8281" y1="53.4275" x2="48.8245" y2="9.2255">
|
||||
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
|
||||
<stop offset="0.6613" style="stop-color:#C41E57"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_3_);" points="49,0 11.6,0 0,47.1 55.6,47.1 "/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="49.8935" y1="-11.5569" x2="48.8588" y2="24.0352">
|
||||
<stop offset="0.5" style="stop-color:#C41E57"/>
|
||||
<stop offset="0.6668" style="stop-color:#D13F48"/>
|
||||
<stop offset="0.7952" style="stop-color:#D94F39"/>
|
||||
<stop offset="0.8656" style="stop-color:#DD5433"/>
|
||||
</linearGradient>
|
||||
<polygon style="fill:url(#SVGID_4_);" points="55.3,47.1 51.1,15.7 49,0 41.7,23 "/>
|
||||
</g>
|
||||
<g>
|
||||
|
||||
<rect x="13.4" y="13.5" transform="matrix(-1 2.577289e-003 -2.577289e-003 -1 70.0288 70.081)" style="fill:#000000;" width="43.2" height="43.2"/>
|
||||
|
||||
<rect x="17.6" y="48.6" transform="matrix(1 -2.577289e-003 2.577289e-003 1 -0.1287 6.634109e-002)" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
|
||||
<path style="fill:#FFFFFF;" d="M17.4,19.1l8.2,0c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1l0,0.1c0,1.5-0.3,2.6-1.1,3.5
|
||||
c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4l-4.6,0l-3.7-5.5l-3.3,0l0,5.5l-3.9,0L17.4,19.1z M25.3,27.8c1,0,1.7-0.2,2.2-0.7
|
||||
c0.5-0.5,0.8-1.1,0.8-1.8l0-0.1c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6l-3.9,0l0,5.1L25.3,27.8z"/>
|
||||
<path style="fill:#FFFFFF;" d="M36,33.2l-1.9,0l0-3.3l2.5,0l0.6-3.8l-2.3,0l0-3.3l2.8,0l0.6-3.7l3.4,0l-0.6,3.7l3.7,0l0.6-3.7
|
||||
l3.4,0l-0.6,3.7l1.9,0l0,3.3l-2.5,0L47,29.9l2.3,0l0,3.3l-2.8,0L45.8,37l-3.4,0l0.7-3.8l-3.7,0L38.7,37l-3.4,0L36,33.2z
|
||||
M43.7,29.9l0.6-3.8l-3.7,0L40,29.9L43.7,29.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |