sourcechord / FluentWPF

Fluent Design System for WPF.
MIT License
1.41k stars 110 forks source link

Resizing from left side jittering and resizing border issue #102

Open milos12345 opened 3 years ago

milos12345 commented 3 years ago

When a window is resized from top-left corner, bottom-left, or left, all controls will jump; This does not happen with other Win32 programs and there is not issue with resizing from the right side. It happens in example program and when a window is complex it is even more noticeable JitteringControls

Second issue is related to the border and here it is compared to notepad. FluentWPF requires the mouse right on the edge, while Notepad and other software will allow resizing several pixels from the edge as seen here ResizeBorder

Please confirm it those are related to WPF or FluenWPF and if there is anything that can be done. Thank you

selastingeorge commented 2 years ago

hi @milos12345 this issue is common to Windows which uses WindowChrome, this can be avoided by handling wndproc and returning a rect with less size than window.

Here is a sample:

Add this code to MainWindow.cs

const int resizeFrameWidth = 11;
const int captionHeight = 33;

public enum HT {
    CLIENT = 1, CAPTION = 2, LEFT = 10, RIGHT, TOP, TOPLEFT, TOPRIGHT, BOTTOM, BOTTOMLEFT, BOTTOMRIGHT
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT {
    public int left, top, right, bottom;
}

[StructLayout(LayoutKind.Sequential)]
public struct Margins {
    public int left, right, top, bottom;
}

[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);

[DllImport("dwmapi.dll")]
public static extern bool DwmDefWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, out IntPtr result);

[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref Margins pMarInset);

protected override void OnSourceInitialized(EventArgs e) {
    base.OnSourceInitialized(e);

    var hWndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);

    hWndSource.AddHook(WndProc);

    // FRAMECHANGED | NOMOVE | NOSIZE
    SetWindowPos(hWndSource.Handle, new IntPtr(), 0, 0, 0, 0, 0x0020 | 0x0002 | 0x0001);
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {

    switch (msg) {
    case 0x0083: // NCCALCSIZE
        if (wParam != IntPtr.Zero) {
            handled = true;
            var client = (RECT) Marshal.PtrToStructure(lParam, typeof (RECT));
            client.Bottom -= 1;
            Marshal.StructureToPtr(client, lParam, false);
        }
        break;
    case 0x0084: // NCHITTEST
        handled = true;

        IntPtr dwmHitTest;
        if (DwmDefWindowProc(hwnd, msg, wParam, lParam, out dwmHitTest)) {
            return dwmHitTest;
        }

        var mousePosition = PointFromScreen(new Point(lParam.ToInt32() & 0xFFFF, lParam.ToInt32() >> 16));

        var isTop = mousePosition.Y <= resizeFrameWidth;
        var isBottom = mousePosition.Y >= ActualHeight - resizeFrameWidth;
        var isLeft = mousePosition.X <= resizeFrameWidth;
        var isRight = mousePosition.X >= ActualWidth - resizeFrameWidth;

        var hitTest = HT.CLIENT;
        if (isTop) {
            if (isLeft) hitTest = HT.TOPLEFT;
            else if (isRight) hitTest = HT.TOPRIGHT;
            else hitTest = HT.TOP;
        } else if (isBottom) {
            if (isLeft) hitTest = HT.BOTTOMLEFT;
            else if (isRight) hitTest = HT.BOTTOMRIGHT;
            else hitTest = HT.BOTTOM;
        } else if (isLeft) hitTest = HT.LEFT;
        else if (isRight) hitTest = HT.RIGHT;
        else if (mousePosition.Y <= captionHeight) hitTest = HT.CAPTION;

        return new IntPtr((int) hitTest);
    }
    return IntPtr.Zero;
}

For now this could help you to solve the issue, if not you can just add NonClientFrameEdges for WindowChrome, i havent tested the NonClientFrameEdges property yet but heard that it will work.

Code Originally Taken From Here : Custom dwm drawn window frame flickers on resizing if the window contains a HwndHost element