当用户在WinUI3 Windows App SDK应用程序中调整主窗口大小时,我希望强制窗口保持16:9的纵横比.我try 在SizeChanged事件处理程序中完成此操作...

private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs args)
{
   var window = sender as MainWindow;
   Windows.Graphics.SizeInt32 y;
   y.Height = (int)args.Size.Height;
   int adjustedWidth = y.Height * 16 / 9;
   y.Width = adjustedWidth;
   window.AppWindow.Resize(y);
}

推荐答案

一种解决方案是使用底层Windows API,因为Windows在调整窗口大小时发送WM_SIZING消息.

为此,您需要能够处理窗口消息.以下是一些带有互操作部分的示例代码,可以实现这一点:

public sealed partial class MainWindow : Window
{
    private readonly WindowProcedureHook _hook;

    public MainWindow()
    {
        this.InitializeComponent();

        // hook the window procedure
        _hook = new WindowProcedureHook(this, WndProc);
    }

    private IntPtr? WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
    {
        // handle the WM_SIZING message
        const int WM_SIZING = 0x0214;
        if (msg == WM_SIZING)
        {
            // get sizing rect
            var rc = Marshal.PtrToStructure<RECT>(lParam);

            // if coming from left/right only, we adjust height
            const int WMSZ_LEFT = 1;
            const int WMSZ_RIGHT = 2;
            if (wParam.ToInt64() == WMSZ_LEFT || wParam.ToInt64() == WMSZ_RIGHT)
            {
                rc.height = rc.width * 9 / 16;
            }
            else
            {
                rc.width = rc.height * 16 / 9;
            }

            // put it back, say we handled it
            Marshal.StructureToPtr(rc, lParam, false);
            return new IntPtr(1);
        }

        return null; // unhandled, let Windows do the job
    }

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

        public int width { get => right - left; set => right = left + value; }
        public int height { get => bottom - top; set => bottom = top + value; }
    }
}

// a utility class to hook window procedure and handle messages, or not
public sealed class WindowProcedureHook
{
    private readonly IntPtr _prevProc;
    private readonly WNDPROC _wndProc;
    private readonly Func<IntPtr, int, IntPtr, IntPtr, IntPtr?> _callback;

    public WindowProcedureHook(Window window, Func<IntPtr, int, IntPtr, IntPtr, IntPtr?> callback)
    {
        ArgumentNullException.ThrowIfNull(window);
        ArgumentNullException.ThrowIfNull(callback);

        _wndProc = WndProc;
        var handle = WinRT.Interop.WindowNative.GetWindowHandle(window);
        _callback = callback;

        const int GWLP_WNDPROC = -4;
        _prevProc = GetWindowLong(handle, GWLP_WNDPROC);
        SetWindowLong(handle, GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(_wndProc));
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) => _callback(hwnd, msg, wParam, lParam) ?? CallWindowProc(_prevProc, hwnd, msg, wParam, lParam);
    private delegate IntPtr WNDPROC(IntPtr handle, int msg, IntPtr wParam, IntPtr lParam);

    private static IntPtr GetWindowLong(IntPtr handle, int index) =>
        IntPtr.Size == 8 ? GetWindowLongPtrW(handle, index) : (IntPtr)GetWindowLongW(handle, index);

    private static IntPtr SetWindowLong(IntPtr handle, int index, IntPtr newLong) =>
        IntPtr.Size == 8 ? SetWindowLongPtrW(handle, index, newLong) : (IntPtr)SetWindowLongW(handle, index, newLong.ToInt32());

    [DllImport("user32")]
    private static extern IntPtr CallWindowProc(IntPtr prevWndProc, IntPtr handle, int msg, IntPtr wParam, IntPtr lParam);

    // note: WinUI3 windows are unicode, so we only use the "W" versions

    [DllImport("user32")]
    private static extern IntPtr GetWindowLongPtrW(IntPtr hWnd, int nIndex);

    [DllImport("user32")]
    private static extern int GetWindowLongW(IntPtr hWnd, int nIndex);

    [DllImport("user32")]
    private static extern int SetWindowLongW(IntPtr hWnd, int nIndexn, int dwNewLong);

    [DllImport("user32")]
    private static extern IntPtr SetWindowLongPtrW(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
}

Csharp相关问答推荐

EF Core. Income和. AsNoTracking正确用法

Polly使用泛型重试和重试包装函数

如何使用XmlSerializer序列化带有CDATA节的XML文件?

如何将DotNet Watch与发布配置和传递给应用程序的参数一起使用?

在.NET 8最低API中从表单绑定中排除属性

当使用Dapper映射DBNull时,我可以抛出异常吗?

异步等待Foreach循环中的ConfigureAWait(FALSE)执行什么操作?

正在从最小API-InvocationConext.Arguments中检索参数的FromBodyAttribute

发布.NET 8 Blazor WebAssembly独立应用程序以进行静态站点部署

我可以强制System.Text.Json.JsonSerializer以非递归方式工作吗?

如何更改Datagridview行标题

使用ITfoxtec.Identity.Saml2解析相同键多值SAML 2声明

实例化列表时的集合表达式是什么?

使用生产环境调试我的应用程序的快速方法

在c#中,使用Okta和Blazor时,LocalReDirect()陷入循环,出现错误&请求太多.

无法创建工具窗口(用于VBIDE、VBA的COM加载项扩展)

使用c#中的Windows 10关机消息

定义可以是两个类之一的类成员

如何从哈希表中获取列表字符串?

NET应用程序如何跟踪websocket流量?