I want to enable SnapLayout
for WPF, because I use Customized Window, according to the documentation, I have to do it myself.
For Win32 apps, make sure you are responding appropriately to WM_NCHITTEST (with a return value of HTMAXBUTTON for the maximize/restore button).
I used the following code
private const int HTMAXBUTTON = 9;
private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wparam,
IntPtr lparam, ref bool handled)
{
switch (msg)
{
case InteropValues.WM_NCHITTEST:
try
{
int x = lparam.ToInt32() & 0xffff;
int y = lparam.ToInt32() >> 16;
var rect = new Rect(_ButtonMax.PointToScreen(
new Point()),
new Size(_ButtonMax.Width, _ButtonMax.Height));
if (rect.Contains(new Point(x, y)))
{
handled = true;
}
return new IntPtr(HTMAXBUTTON);
}
catch (OverflowException)
{
handled = true;
}
break;
}
return IntPtr.Zero;
}
SnapLayout
is displayed well But the maximize button does not work and if I click on it, a button will be created next to it. How can I solve this problem?
Try this way:
Write it in code-behind ([].xaml.cs)
Write it in constructor
this.Loaded += SnapLayoutButton_Loaded;
Next after or before write it:
float scaleFactor;
HwndSource? hwndSource;
private void SnapLayoutButton_Loaded(object sender, RoutedEventArgs e)
{
PresentationSource source = PresentationSource.FromVisual(this);
var dpi = 96.0 * source.CompositionTarget.TransformToDevice.M11;
scaleFactor = (float)(dpi / 96.0);
hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
hwndSource.AddHook(HwndSourceHook);
}
}
private const int WM_NCHITTEST = 0x0084;
private const int WM_NCLBUTTONDOWN = 161;
private const int HTMAXBUTTON = 9;
private bool IsMouseOverFromHook(IntPtr lparam, FrameworkElement button)
{
// Extract mouse coordinates from lparam
int mouseX = (short)(lparam.ToInt32() & 0xFFFF);
int mouseY = (short)((lparam.ToInt32() >> 16) & 0xFFFF);
// Get button's actual dimensions and position
var buttonPosition = button.PointToScreen(new System.Windows.Point(0, 0));
// Check if mouse coordinates are within the button bounds using a single return statement
return mouseX >= buttonPosition.X && mouseX <= buttonPosition.X + button.ActualWidth * scaleFactor && mouseY >= buttonPosition.Y && mouseY <= buttonPosition.Y + button.ActualHeight * scaleFactor;
}
static DependencyPropertyKey s_uiElementIsMouseOverPropertyKey =
(DependencyPropertyKey)typeof(UIElement).GetField("IsMouseOverPropertyKey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)!.GetValue(null)!;
static DependencyPropertyKey s_buttonIsPressedPropertyKey =
(DependencyPropertyKey)typeof(ButtonBase).GetField("IsPressedPropertyKey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)!.GetValue(null)!;
private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
if(msg == WM_NCLBUTTONDOWN)
{
if (IsMouseOverFromHook(lparam, maximizeButton))
{
maximizeButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
}
}
if (msg == WM_NCHITTEST)
{
if (IsMouseOverFromHook(lparam, maximizeButton))
{
maximizeButton.SetValue(s_uiElementIsMouseOverPropertyKey, true);
handled = true;
return new IntPtr(HTMAXBUTTON);
}
else
{
maximizeButton.SetValue(s_uiElementIsMouseOverPropertyKey, false);
if (maximizeButton is ButtonBase button)
{
button.SetValue(s_buttonIsPressedPropertyKey, false);
}
}
}
return IntPtr.Zero;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With