Add some WinUI work
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Interactivity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Toolkit.Foundation;
|
||||
|
||||
@@ -7,14 +7,14 @@ public class AsyncHandlerInitialization<TMessage, TResponse, THandler>(IServiceP
|
||||
IInitialization where THandler : class, IAsyncHandler<TMessage, TResponse>
|
||||
where TMessage : class
|
||||
{
|
||||
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, TResponse>>(provider,
|
||||
async (provider, args) => args.Reply(await provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken)));
|
||||
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, TResponse>>(provider,
|
||||
(provider, args) => args.Reply(provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken)));
|
||||
}
|
||||
|
||||
public class AsyncHandlerInitialization<TMessage, THandler>(IServiceProvider provider) :
|
||||
IInitialization where THandler : class, IAsyncHandler<TMessage>
|
||||
where TMessage : class
|
||||
{
|
||||
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, Unit>>(provider,
|
||||
async (provider, args) => await provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken));
|
||||
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, Unit>>(provider,
|
||||
(provider, args) => provider.GetRequiredService<THandler>().Handle(args.Message, args.CancellationToken));
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Toolkit.Foundation;
|
||||
public class AsyncResponseEventArgs<TMessage, TResponse> :
|
||||
AsyncRequestMessage<TResponse>
|
||||
{
|
||||
public TMessage? Message { get; set; }
|
||||
public required TMessage Message { get; set; }
|
||||
|
||||
public CancellationToken CancellationToken { get; set; }
|
||||
}
|
||||
@@ -20,14 +20,8 @@ public class DefaultHostBuilder :
|
||||
ComponentHostCollection>();
|
||||
|
||||
services.AddSingleton<IDisposer, Disposer>();
|
||||
services.AddSingleton<IMessenger, WeakReferenceMessenger>(_ => WeakReferenceMessenger.Default);
|
||||
services.AddSingleton<IMessenger, StrongReferenceMessenger>(_ => StrongReferenceMessenger.Default);
|
||||
|
||||
//services.AddScoped<SubscriptionCollection>();
|
||||
|
||||
//services.AddTransient<IHandlerProvider, HandlerProvider>();
|
||||
//services.AddScoped<ISubscriber, Subscriber>();
|
||||
//services.AddTransient<IPublisher, Publisher>();
|
||||
//services.AddTransient<IMediator, Mediator>();
|
||||
|
||||
services.AddTransient<IValidation, Validation>();
|
||||
services.AddTransient<IValidatorCollection, ValidatorCollection>();
|
||||
@@ -57,10 +51,10 @@ public class DefaultHostBuilder :
|
||||
services.AddTransient<IComponentFactory, ComponentFactory>();
|
||||
services.AddTransient<IComponentScopeProvider, ComponentScopeProvider>();
|
||||
|
||||
//services.AddHandler<NavigateHandler>();
|
||||
//services.AddHandler<NavigateBackHandler>();
|
||||
services.AddHandler<NavigateEventArgs, NavigateHandler>();
|
||||
services.AddHandler<NavigateBackEventArgs, NavigateBackHandler>();
|
||||
|
||||
//services.AddInitialization<ComponentInitializer>();
|
||||
services.AddInitialization<ComponentInitializer>();
|
||||
services.AddHostedService<AppService>();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ public class HandlerInitialization<TMessage, TResponse, THandler>(IServiceProvid
|
||||
IInitialization where THandler : class, IHandler<TMessage, TResponse>
|
||||
where TMessage : class
|
||||
{
|
||||
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, ResponseEventArgs<TMessage, TResponse>>(provider,
|
||||
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, ResponseEventArgs<TMessage, TResponse>>(provider,
|
||||
(provider, args) => args.Reply(provider.GetRequiredService<THandler>().Handle(args.Message)));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class HandlerInitialization<TMessage, THandler>(IServiceProvider provider
|
||||
IInitialization where THandler : class, IHandler<TMessage>
|
||||
where TMessage : class
|
||||
{
|
||||
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, TMessage>(provider,
|
||||
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, TMessage>(provider,
|
||||
(provider, args) => provider.GetRequiredService<THandler>().Handle(args));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@ public class HandlerKeyedInitialization<TMessage, THandler>(string key, IService
|
||||
IInitialization where THandler : class, IHandler<TMessage>
|
||||
where TMessage : class
|
||||
{
|
||||
public void Initialize() => WeakReferenceMessenger.Default.Register<IServiceProvider, TMessage, string>(provider, key,
|
||||
public void Initialize() => StrongReferenceMessenger.Default.Register<IServiceProvider, TMessage, string>(provider, key,
|
||||
(provider, args) => provider.GetRequiredKeyedService<THandler>(key).Handle(args));
|
||||
}
|
||||
@@ -11,9 +11,27 @@ public static class IMessengerExtensions
|
||||
return args.Response;
|
||||
}
|
||||
|
||||
public static void Send<TMessage>(this IMessenger messenger, string key)
|
||||
where TMessage : class, new() => messenger.Send(new TMessage(), key);
|
||||
public static TResponse Send<TMessage, TResponse>(this IMessenger messenger,
|
||||
TMessage message)
|
||||
where TMessage : class
|
||||
{
|
||||
ResponseEventArgs<TMessage, TResponse> args = messenger.Send(new ResponseEventArgs<TMessage, TResponse> { Message = message });
|
||||
return args.Response;
|
||||
}
|
||||
|
||||
public static void Send<TMessage>(this IMessenger messenger,
|
||||
TMessage message, string key) where TMessage : class =>
|
||||
messenger.Send(message, key);
|
||||
|
||||
public static void Send<TMessage>(this IMessenger messenger,
|
||||
string key) where TMessage : class, new() =>
|
||||
messenger.Send(new TMessage(), key);
|
||||
|
||||
public static async Task<TResponse> SendAsync<TMessage, TResponse>(this IMessenger messenger)
|
||||
where TMessage : class, new() => await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = new TMessage() });
|
||||
where TMessage : class, new() =>
|
||||
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = new TMessage() });
|
||||
|
||||
public static async Task<TResponse> SendAsync<TMessage, TResponse>(this IMessenger messenger,
|
||||
TMessage message) where TMessage : class =>
|
||||
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = message });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Toolkit.Windows;
|
||||
using Toolkit.WinUI;
|
||||
|
||||
namespace Toolkit.UI.WinUI;
|
||||
|
||||
public static class NotifyIconExtensions
|
||||
{
|
||||
public static void SetIcon(this INotifyIcon notifyIcon,
|
||||
Stream? stream)
|
||||
{
|
||||
nint shellTrayHandle = WindowHelper.GetWindowHandle("Shell_TrayWnd");
|
||||
uint dpi = WindowHelper.GetDpi(shellTrayHandle);
|
||||
|
||||
if (stream?.ConvertToIcon(dpi) is Icon icon)
|
||||
{
|
||||
notifyIcon.SetIcon(icon.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,5 +23,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Toolkit.Windows\Toolkit.Windows.csproj" />
|
||||
<ProjectReference Include="..\Toolkit.WinUI\Toolkit.WinUI.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -7,6 +7,9 @@ using Windows.Win32.Graphics.Gdi;
|
||||
using System.Drawing;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using Toolkit.Windows;
|
||||
using Rect = Windows.Foundation.Rect;
|
||||
using WinUIEx;
|
||||
|
||||
namespace Toolkit.UI.WinUI;
|
||||
|
||||
@@ -14,20 +17,78 @@ public static partial class WindowExtensions
|
||||
{
|
||||
private static SUBCLASSPROC? SubClassDelegate;
|
||||
|
||||
public static void SetBorderless(this Window window,
|
||||
public static void Hide(this Window window)
|
||||
{
|
||||
nint handle = WindowNative.GetWindowHandle(window);
|
||||
if (handle == 0) return;
|
||||
|
||||
WindowHelper.HideWindow(new HWND(handle));
|
||||
}
|
||||
|
||||
public static void IsShownInSwitchers(this Window window,
|
||||
bool value)
|
||||
{
|
||||
if (window.AppWindow is AppWindow appWindow &&
|
||||
appWindow.Presenter is OverlappedPresenter presenter)
|
||||
if (window.AppWindow is AppWindow appWindow)
|
||||
{
|
||||
presenter.IsMaximizable = !value;
|
||||
presenter.IsMinimizable = !value;
|
||||
presenter.IsResizable = !value;
|
||||
presenter.SetBorderAndTitleBar(!value, !value);
|
||||
appWindow.IsShownInSwitchers = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTransparency(this Window window,
|
||||
public static void MoveAndResize(this Window window,
|
||||
Rect rect)
|
||||
{
|
||||
nint handle = WindowNative.GetWindowHandle(window);
|
||||
if (handle == 0) return;
|
||||
|
||||
WindowHelper.MoveAndResizeWindow(new HWND(handle),
|
||||
(int)rect.Left,
|
||||
(int)rect.Top,
|
||||
(int)rect.Width,
|
||||
(int)rect.Height);
|
||||
}
|
||||
|
||||
public static void SetBorderless(this Window window,
|
||||
bool value)
|
||||
{
|
||||
WindowStyle windowStyle = window.GetWindowStyle();
|
||||
|
||||
if (value)
|
||||
{
|
||||
windowStyle &= ~(WindowStyle.Caption |
|
||||
WindowStyle.ThickFrame |
|
||||
WindowStyle.Border |
|
||||
WindowStyle.SysMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
windowStyle |= WindowStyle.Caption |
|
||||
WindowStyle.ThickFrame |
|
||||
WindowStyle.Border |
|
||||
WindowStyle.SysMenu;
|
||||
}
|
||||
|
||||
window.SetWindowStyle(windowStyle);
|
||||
}
|
||||
|
||||
public static void SetForeground(this Window window)
|
||||
{
|
||||
nint handle = WindowNative.GetWindowHandle(window);
|
||||
if (handle == 0) return;
|
||||
|
||||
WindowHelper.SetForegroundWindow(new HWND(handle));
|
||||
}
|
||||
|
||||
public static void SetTopMost(this Window window,
|
||||
bool value)
|
||||
{
|
||||
if (window.AppWindow is AppWindow appWindow &&
|
||||
appWindow.Presenter is OverlappedPresenter presenter)
|
||||
{
|
||||
presenter.IsAlwaysOnTop = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTransparency(this Window window,
|
||||
bool value)
|
||||
{
|
||||
nint handle = WindowNative.GetWindowHandle(window);
|
||||
@@ -44,18 +105,12 @@ public static partial class WindowExtensions
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void EnableTransparency(HWND hWnd)
|
||||
public static void Show(this Window window)
|
||||
{
|
||||
SubClassDelegate = new SUBCLASSPROC(WindowSubClass);
|
||||
_ = PInvoke.SetWindowSubclass(hWnd, SubClassDelegate, 0, 0);
|
||||
nint handle = WindowNative.GetWindowHandle(window);
|
||||
if (handle == 0) return;
|
||||
|
||||
WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE,
|
||||
(int)(exStyle | WINDOW_EX_STYLE.WS_EX_LAYERED));
|
||||
|
||||
COLORREF blackColor = new COLORREF((uint)ToWin32(Color.Black));
|
||||
_ = PInvoke.SetLayeredWindowAttributes(hWnd, blackColor, 0, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_COLORKEY |
|
||||
LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_ALPHA);
|
||||
WindowHelper.ShowWindow(new HWND(handle));
|
||||
}
|
||||
|
||||
private static unsafe void DisableTransparency(HWND hWnd)
|
||||
@@ -70,6 +125,20 @@ public static partial class WindowExtensions
|
||||
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)(exStyle & ~WINDOW_EX_STYLE.WS_EX_LAYERED));
|
||||
}
|
||||
|
||||
private static unsafe void EnableTransparency(HWND hWnd)
|
||||
{
|
||||
SubClassDelegate = new SUBCLASSPROC(WindowSubClass);
|
||||
_ = PInvoke.SetWindowSubclass(hWnd, SubClassDelegate, 0, 0);
|
||||
|
||||
WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE,
|
||||
(int)(exStyle | WINDOW_EX_STYLE.WS_EX_LAYERED));
|
||||
|
||||
COLORREF blackColor = new COLORREF((uint)ToWin32(Color.Black));
|
||||
_ = PInvoke.SetLayeredWindowAttributes(hWnd, blackColor, 0, LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_COLORKEY |
|
||||
LAYERED_WINDOW_ATTRIBUTES_FLAGS.LWA_ALPHA);
|
||||
}
|
||||
|
||||
private static int ToWin32(Color c) => c.B << 16 | c.G << 8 | c.R;
|
||||
|
||||
private static unsafe LRESULT WindowSubClass(HWND hWnd,
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
using Toolkit.Foundation;
|
||||
|
||||
namespace Toolkit.WinUI;
|
||||
|
||||
public class ContentTemplate :
|
||||
DataTemplateSelector,
|
||||
IContentTemplate
|
||||
{
|
||||
protected override DataTemplate? SelectTemplateCore(object item)
|
||||
{
|
||||
if (item is IObservableViewModel observableViewModel)
|
||||
{
|
||||
if (observableViewModel.Provider is IServiceProvider provider)
|
||||
{
|
||||
Type itemType = item.GetType();
|
||||
if (provider.GetRequiredKeyedService<IContentTemplateDescriptor>(itemType.Name.Replace("ViewModel", ""))
|
||||
is IContentTemplateDescriptor descriptor)
|
||||
{
|
||||
return CreateDataTemplate(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
protected override DataTemplate? SelectTemplateCore(object item,
|
||||
DependencyObject container) => SelectTemplateCore(item);
|
||||
|
||||
private static DataTemplate CreateDataTemplate(IContentTemplateDescriptor descriptor)
|
||||
{
|
||||
string xamlString = @$"
|
||||
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
|
||||
xmlns:local=""using:Toolkit.WinUI"">
|
||||
<local:TemplateControl />
|
||||
</DataTemplate>";
|
||||
|
||||
return (DataTemplate)XamlReader.Load(xamlString);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ public static class IServiceCollectionExtensions
|
||||
services.AddTransient<IDispatcherTimerFactory, DispatcherTimerFactory>();
|
||||
services.AddSingleton<IWindowRegistry, WindowRegistry>();
|
||||
|
||||
services.AddTransient<IContentTemplate, ContentTemplate>();
|
||||
|
||||
services.AddTransient((Func<IServiceProvider, IProxyServiceCollection<IComponentBuilder>>)(provider =>
|
||||
new ProxyServiceCollection<IComponentBuilder>(services =>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Toolkit.Foundation;
|
||||
|
||||
namespace Toolkit.WinUI;
|
||||
|
||||
[Bindable]
|
||||
public class TemplateControl :
|
||||
ContentControl
|
||||
{
|
||||
public TemplateControl()
|
||||
{
|
||||
DefaultStyleKey = typeof(TemplateControl);
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender,
|
||||
RoutedEventArgs args)
|
||||
{
|
||||
Loaded -= OnLoaded;
|
||||
|
||||
if (DataContext is IObservableViewModel observableViewModel)
|
||||
{
|
||||
if (observableViewModel.Provider is IServiceProvider provider)
|
||||
{
|
||||
if (provider.GetRequiredKeyedService<IContentTemplateDescriptor>(DataContext.GetType().Name.Replace("ViewModel", ""))
|
||||
is IContentTemplateDescriptor descriptor)
|
||||
{
|
||||
if (provider.GetRequiredKeyedService(descriptor.TemplateType, descriptor.Key)
|
||||
is FrameworkElement control)
|
||||
{
|
||||
void HandleLoaded(object? sender, RoutedEventArgs args)
|
||||
{
|
||||
control.Loaded -= HandleLoaded;
|
||||
if (control.DataContext is object content)
|
||||
{
|
||||
if (content is IActivation activation)
|
||||
{
|
||||
activation.IsActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleDataContextChanged(FrameworkElement? sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if (control.DataContext is object content)
|
||||
{
|
||||
if (content is IActivation activation)
|
||||
{
|
||||
activation.IsActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleUnloaded(object? sender, RoutedEventArgs args)
|
||||
{
|
||||
control.Unloaded -= HandleUnloaded;
|
||||
if (control.DataContext is object content)
|
||||
{
|
||||
if (content is IActivation activation)
|
||||
{
|
||||
activation.IsActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
control.Loaded += HandleLoaded;
|
||||
control.Unloaded += HandleUnloaded;
|
||||
control.DataContextChanged += HandleDataContextChanged;
|
||||
|
||||
Content = control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,13 @@
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<WindowsSdkPackageVersion>10.0.19041.41</WindowsSdkPackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.6.240923002" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Toolkit.Foundation\Toolkit.Foundation.csproj" />
|
||||
<ProjectReference Include="..\Toolkit.Windows\Toolkit.Windows.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
namespace Toolkit.Windows;
|
||||
|
||||
public interface IPointerMonitor :
|
||||
public interface IPointer :
|
||||
IInitialization,
|
||||
IDisposable;
|
||||
@@ -1,41 +1,51 @@
|
||||
SetWindowsHookEx
|
||||
GetModuleHandle
|
||||
CallNextHookEx
|
||||
GetPhysicalCursorPos
|
||||
FindWindowEx
|
||||
FindWindow
|
||||
GetWindowRect
|
||||
DestroyWindow
|
||||
DefWindowProcW
|
||||
CallNextHookEx
|
||||
CreateSolidBrush
|
||||
CreateWindowExW
|
||||
RegisterClassW
|
||||
GetSystemMetrics
|
||||
MonitorFromWindow
|
||||
RegisterWindowMessage
|
||||
GetDpiForWindow
|
||||
SetWindowPos
|
||||
SHCreateShellItemArrayFromDataObject
|
||||
Shell_NotifyIcon
|
||||
GetSystemMetricsForDpi
|
||||
GetSystemMetrics
|
||||
DWM_WINDOW_CORNER_PREFERENCE
|
||||
DefSubclassProc
|
||||
DefWindowProcW
|
||||
DeleteObject
|
||||
DestroyWindow
|
||||
DwmSetWindowAttribute
|
||||
FillRect
|
||||
FindWindow
|
||||
FindWindowEx
|
||||
GetClientRect
|
||||
GetCurrentProcess
|
||||
SetProcessInformation
|
||||
PROCESS_POWER_THROTTLING_STATE
|
||||
GetDpiForWindow
|
||||
GetPhysicalCursorPos
|
||||
GetSystemMetrics
|
||||
GetSystemMetricsForDpi
|
||||
GetWindowLong
|
||||
GetWindowRect
|
||||
MonitorFromWindow
|
||||
PROCESS_POWER_THROTTLING_CURRENT_VERSION
|
||||
PROCESS_POWER_THROTTLING_EXECUTION_SPEED
|
||||
SetPriorityClass
|
||||
WINDOW_STYLE
|
||||
DefSubclassProc
|
||||
SetLayeredWindowAttributes
|
||||
WM_ERASEBKGND
|
||||
SetWindowSubclass
|
||||
GetClientRect
|
||||
CreateSolidBrush
|
||||
DwmSetWindowAttribute
|
||||
DWM_WINDOW_CORNER_PREFERENCE
|
||||
FillRect
|
||||
SetLayeredWindowAttributes
|
||||
DeleteObject
|
||||
PROCESS_POWER_THROTTLING_STATE
|
||||
RegisterClassW
|
||||
RegisterWindowMessage
|
||||
RemoveWindowSubclass
|
||||
GetWindowLong
|
||||
SetWindowLong
|
||||
SHCreateShellItemArrayFromDataObject
|
||||
SetLayeredWindowAttributes
|
||||
SetPriorityClass
|
||||
SetProcessInformation
|
||||
SetWindowLong
|
||||
SetWindowPos
|
||||
SetWindowSubclass
|
||||
SetWindowsHookEx
|
||||
Shell_NotifyIcon
|
||||
WINDOW_STYLE
|
||||
WM_ERASEBKGND
|
||||
SetForegroundWindow
|
||||
ShowWindow
|
||||
GetCursorPos
|
||||
UnregisterClass
|
||||
CreateWindowEx
|
||||
RegisterClass
|
||||
DefWindowProc
|
||||
GetMessage
|
||||
TranslateMessage
|
||||
DispatchMessage
|
||||
PostQuitMessage
|
||||
DestroyWindow
|
||||
GetModuleHandle
|
||||
@@ -1,11 +1,12 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using Toolkit.Foundation;
|
||||
using Windows.Win32;
|
||||
|
||||
namespace Toolkit.Windows;
|
||||
|
||||
|
||||
public partial class NotifyIcon(IWndProc wndProc,
|
||||
public class NotifyIcon(IWndProc wndProc,
|
||||
IMessenger messenger) :
|
||||
INotifyIcon,
|
||||
IRecipient<WndProcEventArgs>
|
||||
@@ -17,11 +18,6 @@ public partial class NotifyIcon(IWndProc wndProc,
|
||||
private bool isDisposed;
|
||||
private NotifyIconData notifyIconData;
|
||||
|
||||
~NotifyIcon()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
private enum NotifyIconBalloonType
|
||||
{
|
||||
None = 0x00,
|
||||
@@ -66,6 +62,14 @@ public partial class NotifyIcon(IWndProc wndProc,
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public unsafe PointerLocation GetPointerPosition()
|
||||
{
|
||||
Point point = new();
|
||||
_ = PInvoke.GetCursorPos(&point);
|
||||
|
||||
return new PointerLocation(point.X, point.Y);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
messenger.RegisterAll(this);
|
||||
@@ -79,15 +83,18 @@ public partial class NotifyIcon(IWndProc wndProc,
|
||||
switch (message.LParam)
|
||||
{
|
||||
case (uint)WndProcMessages.WM_LBUTTONUP:
|
||||
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Left));
|
||||
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Left,
|
||||
GetPointerPosition()));
|
||||
break;
|
||||
|
||||
case (uint)WndProcMessages.WM_MBUTTONUP:
|
||||
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Middle));
|
||||
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Middle,
|
||||
GetPointerPosition()));
|
||||
break;
|
||||
|
||||
case (uint)WndProcMessages.WM_RBUTTONUP:
|
||||
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Right));
|
||||
messenger.Send(new NotifyIconInvokedEventArgs(PointerButton.Right,
|
||||
GetPointerPosition()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
namespace Toolkit.Windows;
|
||||
|
||||
public record NotifyIconInvokedEventArgs(PointerButton PointerButton);
|
||||
public record NotifyIconInvokedEventArgs(PointerButton Button,
|
||||
PointerLocation Location);
|
||||
|
||||
@@ -59,4 +59,9 @@ public static partial class PInvoke
|
||||
|
||||
public static void GetAppBarPosition(ref AppBarData appBarData) =>
|
||||
SHAppBarMessage(AppBarMessage.GetTaskbarPos, ref appBarData);
|
||||
|
||||
internal static bool SetWindowSubclass(HWND value1, Func<HWND, uint, WPARAM, LPARAM, nuint, nuint, LRESULT> value2, int v1, nuint v2)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Toolkit.Windows;
|
||||
|
||||
public class PointerMonitor(IMessenger messenger) :
|
||||
IPointerMonitor
|
||||
public class Pointer(IMessenger messenger) :
|
||||
IPointer
|
||||
{
|
||||
private bool isDisposed;
|
||||
private bool isPointerDrag;
|
||||
@@ -16,7 +16,7 @@ public class PointerMonitor(IMessenger messenger) :
|
||||
private HOOKPROC? mouseEventDelegate;
|
||||
private UnhookWindowsHookExSafeHandle? mouseHandle;
|
||||
|
||||
~PointerMonitor()
|
||||
~Pointer()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
@@ -126,9 +126,9 @@ public class PointerMonitor(IMessenger messenger) :
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe bool TryGetPointer(out Point point)
|
||||
private unsafe bool TryGetPointer(out System.Drawing.Point point)
|
||||
{
|
||||
fixed (Point* lpPointLocal = &point)
|
||||
fixed (System.Drawing.Point* lpPointLocal = &point)
|
||||
{
|
||||
return PInvoke.GetPhysicalCursorPos(lpPointLocal);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ public class PointerMonitor(IMessenger messenger) :
|
||||
|
||||
private bool TryGetPointerLocation([MaybeNullWhen(false)] out PointerLocation location)
|
||||
{
|
||||
if (TryGetPointer(out Point point))
|
||||
if (TryGetPointer(out System.Drawing.Point point))
|
||||
{
|
||||
location = new PointerLocation(point.X, point.Y);
|
||||
return true;
|
||||
@@ -16,7 +16,10 @@ public record Rect
|
||||
}
|
||||
|
||||
public int X { get; }
|
||||
|
||||
public int Y { get; }
|
||||
|
||||
public int Width { get; }
|
||||
|
||||
public int Height { get; }
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public class Taskbar(IMessenger messenger,
|
||||
return state;
|
||||
}
|
||||
|
||||
public IntPtr GetHandle() => WindowHelper.Find("Shell_TrayWnd");
|
||||
public IntPtr GetHandle() => WindowHelper.FindWindow("Shell_TrayWnd");
|
||||
|
||||
public void Receive(WndProcEventArgs args)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ public class Taskbar(IMessenger messenger,
|
||||
public void Receive(PointerMovedEventArgs args)
|
||||
{
|
||||
nint taskbarHandle = GetHandle();
|
||||
if (WindowHelper.TryGetBounds(taskbarHandle, out Rect? rect))
|
||||
if (WindowHelper.TryGetWindowBounds(taskbarHandle, out Rect? rect))
|
||||
{
|
||||
if (args.Location.IsWithinBounds(rect))
|
||||
{
|
||||
|
||||
@@ -49,7 +49,7 @@ public class TaskbarButtonMonitor :
|
||||
taskListHandle = taskbarList.GetHandle();
|
||||
taskListElement = clientUIAutomation.ElementFromHandle(taskListHandle);
|
||||
|
||||
if (WindowHelper.TryGetBounds(taskListHandle, out Rect? rect))
|
||||
if (WindowHelper.TryGetWindowBounds(taskListHandle, out Rect? rect))
|
||||
{
|
||||
taskbarRectCache = rect;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public class TaskbarButtonMonitor :
|
||||
|
||||
private bool CheckDirtyTaskbarRegion()
|
||||
{
|
||||
if (WindowHelper.TryGetBounds(taskListHandle, out Rect? rect))
|
||||
if (WindowHelper.TryGetWindowBounds(taskListHandle, out Rect? rect))
|
||||
{
|
||||
if (taskbarRectCache?.Width != rect.Width ||
|
||||
taskbarRectCache?.Height != rect.Height)
|
||||
|
||||
@@ -5,8 +5,8 @@ public class TaskbarList(ITaskbar taskbar) :
|
||||
{
|
||||
public IntPtr GetHandle()
|
||||
{
|
||||
nint rebarHandle = WindowHelper.Find("ReBarWindow32", taskbar.GetHandle());
|
||||
nint taskHandle = WindowHelper.Find("MSTaskSwWClass", rebarHandle);
|
||||
return WindowHelper.Find("MSTaskListWClass", taskHandle);
|
||||
nint rebarHandle = WindowHelper.FindWindow("ReBarWindow32", taskbar.GetHandle());
|
||||
nint taskHandle = WindowHelper.FindWindow("MSTaskSwWClass", rebarHandle);
|
||||
return WindowHelper.FindWindow("MSTaskListWClass", taskHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,35 +7,44 @@ namespace Toolkit.Windows;
|
||||
|
||||
public class WindowHelper
|
||||
{
|
||||
public static IntPtr GetHandle(string windowName) => PInvoke.FindWindow(windowName, null);
|
||||
public static IntPtr FindWindow(string name) =>
|
||||
PInvoke.FindWindow(name, null);
|
||||
|
||||
public static uint GetDpi(IntPtr handle) => PInvoke.GetDpiForWindow((HWND)handle);
|
||||
public static IntPtr FindWindow(string name, IntPtr handle) =>
|
||||
PInvoke.FindWindowEx(new HWND(handle), new HWND(), name, null);
|
||||
|
||||
public static void BringToForeground(HWND handle)
|
||||
{
|
||||
if (TryGetBoundsUnsafe(handle, out RECT bounds))
|
||||
{
|
||||
PInvoke.SetWindowPos(handle, new HWND(), bounds.left, bounds.top, bounds.right -
|
||||
bounds.left, bounds.bottom - bounds.top, SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
public static uint GetDpi(IntPtr handle) =>
|
||||
PInvoke.GetDpiForWindow((HWND)handle);
|
||||
|
||||
public static IntPtr Find(string windowName) =>
|
||||
PInvoke.FindWindow(windowName, null);
|
||||
public static IntPtr GetWindowHandle(string name) =>
|
||||
PInvoke.FindWindow(name, null);
|
||||
|
||||
public static IntPtr Find(string windowName, IntPtr parentHandle) =>
|
||||
PInvoke.FindWindowEx(new HWND(parentHandle), new HWND(), windowName, null);
|
||||
public static bool HideWindow(IntPtr hWnd) =>
|
||||
PInvoke.ShowWindow(new HWND(hWnd), SHOW_WINDOW_CMD.SW_HIDE);
|
||||
|
||||
public static void MoveAndResize(HWND handle, int x, int y, int width, int height) =>
|
||||
public static void MoveAndResizeWindow(HWND handle, int x, int y, int width, int height) =>
|
||||
PInvoke.SetWindowPos(handle, new HWND(), x, y, width, height, 0);
|
||||
|
||||
public static bool TryGetBounds(IntPtr handle,
|
||||
public static bool SetForegroundWindow(HWND handle)
|
||||
{
|
||||
if (TryGetWindowBoundsUnsafe(handle, out RECT bounds))
|
||||
{
|
||||
return PInvoke.SetWindowPos(handle, new HWND(), bounds.left, bounds.top, bounds.right -
|
||||
bounds.left, bounds.bottom - bounds.top, SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE) == 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ShowWindow(IntPtr hWnd) =>
|
||||
PInvoke.ShowWindow(new HWND(hWnd), SHOW_WINDOW_CMD.SW_SHOW);
|
||||
|
||||
public static bool TryGetWindowBounds(IntPtr handle,
|
||||
[MaybeNullWhen(false)] out Rect rect)
|
||||
{
|
||||
if (TryGetBoundsUnsafe(handle, out RECT unsafeRect))
|
||||
if (TryGetWindowBoundsUnsafe(handle, out RECT unsafeRect))
|
||||
{
|
||||
rect = new Rect(unsafeRect.left, unsafeRect.top, unsafeRect.right - unsafeRect.left, unsafeRect.bottom - unsafeRect.top);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -43,7 +52,7 @@ public class WindowHelper
|
||||
return false;
|
||||
}
|
||||
|
||||
private static unsafe bool TryGetBoundsUnsafe(IntPtr handle, out RECT rect)
|
||||
private static unsafe bool TryGetWindowBoundsUnsafe(IntPtr handle, out RECT rect)
|
||||
{
|
||||
fixed (RECT* lpRectLocal = &rect)
|
||||
{
|
||||
|
||||
+42
-37
@@ -1,7 +1,7 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Toolkit.Foundation;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Gdi;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
namespace Toolkit.Windows;
|
||||
@@ -10,56 +10,61 @@ public class WndProc(IMessenger messenger) :
|
||||
IWndProc
|
||||
{
|
||||
private WNDPROC? handler;
|
||||
private bool isDisposed;
|
||||
|
||||
~WndProc()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public IntPtr Handle { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void Initialize() => InitializeWndProc();
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isDisposed = true;
|
||||
|
||||
PInvoke.DestroyWindow((HWND)Handle);
|
||||
}
|
||||
private LRESULT HandleWndProc(HWND hWnd, uint msg,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
messenger.Send(new WndProcEventArgs(msg,
|
||||
(uint)wParam.Value,
|
||||
(uint)lParam.Value));
|
||||
|
||||
return PInvoke.DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
private unsafe void InitializeWndProc()
|
||||
{
|
||||
string windowName = Guid.NewGuid().ToString();
|
||||
handler = Wndproc;
|
||||
string windowId = $"WndProc_Handler_{Guid.NewGuid()}";
|
||||
handler = HandleWndProc;
|
||||
|
||||
WNDCLASSW wndProcWindow;
|
||||
|
||||
wndProcWindow.style = 0;
|
||||
wndProcWindow.lpfnWndProc = handler;
|
||||
wndProcWindow.cbClsExtra = 0;
|
||||
wndProcWindow.cbWndExtra = 0;
|
||||
wndProcWindow.hInstance = new HINSTANCE();
|
||||
wndProcWindow.hIcon = new HICON();
|
||||
wndProcWindow.hCursor = new HCURSOR();
|
||||
wndProcWindow.hbrBackground = new HBRUSH();
|
||||
|
||||
fixed (char* menuName = "")
|
||||
fixed (char* className = windowId)
|
||||
{
|
||||
wndProcWindow.lpszMenuName = new PCWSTR(menuName);
|
||||
WNDCLASSW wndCLass = new()
|
||||
{
|
||||
lpfnWndProc = handler,
|
||||
lpszClassName = className,
|
||||
};
|
||||
|
||||
_ = PInvoke.RegisterClass(wndCLass);
|
||||
}
|
||||
|
||||
fixed (char* className = windowName)
|
||||
{
|
||||
wndProcWindow.lpszClassName = new PCWSTR(className);
|
||||
}
|
||||
|
||||
PInvoke.RegisterClass(wndProcWindow);
|
||||
Handle = PInvoke.CreateWindowEx(0, wndProcWindow.lpszClassName,
|
||||
new PCWSTR(), 0, 0, 0, 0, 0, new HWND(),
|
||||
new HMENU(),
|
||||
new HINSTANCE());
|
||||
}
|
||||
|
||||
private LRESULT Wndproc(HWND param0, uint param1, WPARAM param2, LPARAM param3)
|
||||
{
|
||||
messenger.Send(new WndProcEventArgs(param1, (uint)param2.Value, (uint)param3.Value));
|
||||
return PInvoke.DefWindowProc(param0, param1, param2, param3);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
InitializeWndProc();
|
||||
Handle = PInvoke.CreateWindowEx(0, windowId, windowId, 0, 0, 0, 0, 0,
|
||||
new HWND(IntPtr.Zero), null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user