If user double-clicks window title bar to maximize window, the window will maximize on MouseDown event of the second click, but then the MouseUp event on that same second click will be registered by one of the controls in the window that are now under the cursor and trigger something user didn't want.
How can it be prevented?
This should work just fine:
Solution:
//WNDPROC INTEROP
private const int WM_NCLBUTTONDBLCLK = 0x00A3;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
//TITLE BAR DOUBLE CLICK
if (msg == WM_NCLBUTTONDBLCLK)
{
Console.WriteLine("titlebar double click " + this.WindowState);
//WINDOW ABOUT TO GET MAXIMIZED
if (msg == WM_NCLBUTTONDBLCLK)
handleNextMouseup = true;
else if (msg == 0x202) // mouseup
{
if (handleNextMouseup)
handled = true;
handleNextMouseup = false;
}
}
return IntPtr.Zero;
}
another possible solution:
//WNDPROC INTEROP
private const int WM_NCLBUTTONDBLCLK = 0x00A3;
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
//TITLE BAR DOUBLE CLICK
if (msg == WM_NCLBUTTONDBLCLK)
{
Console.WriteLine("titlebar double click " + this.WindowState);
//WINDOW ABOUT TO GET MAXIMIZED
if (this.WindowState == WindowState.Normal)
{
fakehittestvisible = true;
}
}
return IntPtr.Zero;
}
private bool fakehittestvisible = false;
//ON PREVIEW MOUSE UP ABORT IF MIXIMIZING HAPPENED
private void this_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (fakehittestvisible)
{
e.Handled = true;
fakehittestvisible = false;
return;
}
fakehittestvisible = false;
Console.WriteLine("this mouse up state is " + this.WindowState);
}
Related
The reported issue occurs when the check box in below image(This PC -->Properties-->Advanced System Settings-->(under Performance in Advanced tab click Settings)) is disabled.
Try to get the mouse cursor position while dragging a window in WPF. The location of window is updated only when mouse is pressed and released, not when it window dragged.
public partial class MainWindow : Window
{
private const int WM_MOVING = 0x0216;
private HwndSource _hwndSrc;
private HwndSourceHook _hwndSrcHook;
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
this.Unloaded += MainWindow_Unloaded;
}
private void MainWindow_Unloaded(object sender, RoutedEventArgs e)
{
_hwndSrc.RemoveHook(_hwndSrcHook);
_hwndSrc.Dispose();
_hwndSrc = null;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_hwndSrc = HwndSource.FromDependencyObject(this) as HwndSource;
_hwndSrcHook = FilterMessage;
_hwndSrc.AddHook(_hwndSrcHook);
}
private IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_MOVING:
OnLocationChange();
break;
}
return IntPtr.Zero;
}
private void OnLocationChange()
{
Rect windowRect = new Rect(this.Left, this.Top, this.Width, this.Height);
}
}
Need the location of window to update when it is dragged by mouse.
I want to show a window with a custom region and a custom appearance. I hook a window proc and set the custom region on WM_SIZE message by SetWindowRgn function. Also i process a WM_NCCALCSIZE to remove standard window frame.
[SecuritySafeCritical]
protected virtual IntPtr HwndSourceHookHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
if(msg == WinApi.WM_NCCALCSIZE) {
handled = true;
return IntPtr.Zero;
}
if(msg == WinApi.WM_SIZE) {
if(region != IntPtr.Zero)
WinApi.DeleteObject(region);
int width = lParam.ToInt32() & 0xFFFF;
int height = lParam.ToInt32() >> 16;
region = WinApi.CreateRoundRectRgn(0, 0, width, height, 40, 40);
WinApi.SetWindowRgn(new WindowInteropHelper(this).Handle, region, true);
}
return IntPtr.Zero;
}
The window is appeared on my Windows 8.1 OS with a round corners as expected and without border and window buttons. But i notice that in this case window is closed immediately without performing the close animation. If i comment SetWindowRgn, all works fine. Anyone knows what i am doing wrong?
The animation is being performed in the Window. Therefore, you need to stop the Window from actually closing when the close Button is pressed and start the animation then instead. When the animation is complete, then you should close the Window. This can be achieved as follows:
Handle the Window.Closing and Window.Close events:
private void AnimationWindow_Closing(object sender, CancelEventArgs e)
{
if (!isCloseAnimationComplete)
{
e.Cancel = true;
CloseWindow();
}
}
private void AnimationWindow_Close(object sender, RoutedEventArgs e)
{
CloseWindow();
}
public void CloseWindow()
{
// Set up animation
animation.Completed += CloseAnimation_Completed;
// Start animation
}
private void CloseAnimation_Completed(object sender, EventArgs e)
{
isCloseAnimationComplete = true;
// Actually close Window here
Close();
}
I'm trying to anchor a WPF Window (NOT a control inside a window) to TopRight for example, by default Windows anchors all windows to top left.
I tried the following code
private void OnWindowSizeChanged(object sender, SizeChangedEventArgs e)
{
double delta = e.PreviousSize.Width - e.NewSize.Width;
Left += delta;
}
It works, but the window stutters/flickers during rapid size changes (e.g Animations)
I tried googling it but did not find a good solution, am I missing something ?
I managed to solve the problem with the help of this post.
Here's the code
public partial class MainWindow : Window
{
private double right;
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
right = Left + Width;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == (int)WindowMessage.WindowPositionChanging)
{
var windowPosition = (WindowPosition)Marshal.PtrToStructure(lParam, typeof(WindowPosition));
bool isMove = !windowPosition.Flags.HasFlag(WindowPositionFlags.NoMove); //0x0002
bool isSize = !windowPosition.Flags.HasFlag(WindowPositionFlags.NoSize); //0x0001
if (isMove)
{
right = windowPosition.Left + windowPosition.Width;
}
else if (isSize)
{
windowPosition.Left = (int)(right - windowPosition.Width);
windowPosition.Top = (int)Top;
windowPosition.Flags = (WindowPositionFlags)((int)windowPosition.Flags & 0xfffd); //remove the NoMove flag
Marshal.StructureToPtr(windowPosition, lParam, true);
}
}
return IntPtr.Zero;
}
Hope it helps someone
How can I handle tilt left or tilt right mouse event in WPF?
alt text http://s3images.coroflot.com/user_files/individual_files/featured/featured_1266_st_dVYgtBSHIQRPzXvrG4WnUW.jpg
I figured out how to implement WndProc in WPF UserControl. UserControl must obtain a window pointer like by AppendWindow method in my example:
private static MyUserControl instanceWithFocus;
public void AppendWindow(Window window) {
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(window).Handle);
source.AddHook(new HwndSourceHook(WndProc));
}
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
switch (msg) {
case Win32Messages.WM_MOUSEHWHEEL:
MouseWheelTilt(wParam, lParam);
handled = true;
break;
default:
break;
}
return IntPtr.Zero;
}
private static void MouseWheelTilt(IntPtr wParam, IntPtr lParam) {
Int32 tilt = (Int16)Utils.HIWORD(wParam);
Int32 keys = Utils.LOWORD(wParam);
Int32 x = Utils.LOWORD(lParam);
Int32 y = Utils.HIWORD(lParam);
// call an event on active instance of this object
if (instanceWithFocus != null) {
instanceWithFocus.MouseWheelTilt(tilt, keys, x, y);
}
}
private void MouseWheelTilt(Int32 tilt, Int32 keys, Int32 x, Int32 y) {
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + tilt);
}
private void UserControl_MouseEnter(object sender, MouseEventArgs e) {
instanceWithFocus = this;
}
private void UserControl_MouseLeave(object sender, MouseEventArgs e) {
instanceWithFocus = null;
}
abstract class Win32Messages {
public const int WM_MOUSEHWHEEL = 0x020E;
}
abstract class Utils {
internal static Int32 HIWORD(IntPtr ptr) {
Int32 val32 = ptr.ToInt32();
return ((val32 >> 16) & 0xFFFF);
}
internal static Int32 LOWORD(IntPtr ptr) {
Int32 val32 = ptr.ToInt32();
return (val32 & 0xFFFF);
}
}
If I use dragMove the wpf window will not move to a location where the y value is negative. I can however set the windows top value to a negative value. Is there a simple way to enable dragMove to allow the top of the window to be moved above the displays 0 position?
Edit:
It seems that this is the default window's handling of moveWindow. Verified with a call to SendMessage( hwnd, WM_SYSCOMMAND, SC_MOVE, null);
As I found, the window will move to "negative" location, but will then jump back. To prevent this you could do something like:
public partial class Window1: Window {
public Window1() {
InitializeComponent();
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
DragMove();
}
public struct WINDOWPOS {
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public UInt32 flags;
};
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
switch(msg) {
case 0x46://WM_WINDOWPOSCHANGING
if(Mouse.LeftButton != MouseButtonState.Pressed) {
WINDOWPOS wp = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
wp.flags = wp.flags | 2; //SWP_NOMOVE
Marshal.StructureToPtr(wp, lParam, false);
}
break;
}
return IntPtr.Zero;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
}
}
Handling WM_WINDOWPOSCHANGING this way will prevent any movement of the window unless left mouse button is pressed. This includes maximizing the window and programmatic change of window position as well, so you'll have to adapt the code if you need another behavior.