WPF:使窗口不可调整大小,但保留框架?

发布于 2024-09-12 02:28:00 字数 724 浏览 3 评论 0原文

我有一个没有标题栏的窗口(WindowStyle == WindowStyle.None)。整个窗户采用了 Aero 玻璃效果。当我使窗口不可调整大小(ResizeMode == ResizeMode.NoResize)时,玻璃效果消失,我的控件只是挂在半空中。 (本质上,窗口本身消失了,但留下了它的内容。)

有没有办法让我在不删除窗框的情况下使窗口不可调整大小?


我已阅读问题在 a 上启用 Vista 玻璃效果无边框 WPF 窗口,但这并不是我想要的——我想保留窗口边框。有关我希望窗口的外观的示例,请在启用 Aero 的情况下按 Alt+Tab。


澄清一下,当鼠标悬停在窗口边框上时,我根本不希望显示调整大小光标。这基本上就是我希望我的窗口看起来像的样子:

Projector

该解决方案不必严格是 WPF——我可以通过使用 Win32 API 来实现这一点。

I have a window that does not have a title bar (WindowStyle == WindowStyle.None). The entire window uses the Aero glass effect. When I make the window unresizeable (ResizeMode == ResizeMode.NoResize), the glass effect disappears and my controls just hang in midair. (Essentially, the window itself disappears but leaves its contents.)

Is there a way for me to make the window unresizeable without getting rid of the window frame?


I have read the question Enable Vista glass effect on a borderless WPF window, but that's not quite what I want--I would like to keep the window border. For an example of what I would like my window to look like, hit Alt+Tab with Aero enabled.


To clarify, I do no want the resize cursors to show up at all when hovering over the window border. This is essentially what I want my window to look like:

Projector

The solution doesn't have to be strictly WPF--I am fine with hacking around with the Win32 API in order to achieve this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

别把无礼当个性 2024-09-19 02:28:00

您可以挂钩 wndproc 并拦截 WM_WINDOWPOSCHANGING信息。严格来说不是 WPF,但可能是您最好的选择。

如果您想隐藏调整大小光标,那么最好的选择是拦截 WM_NCHITTEST。调用DefWindowProc(获取默认行为),并测试返回值;如果是HTBOTTOM、HTBOTTOMLEFT、HTBOTTOMRIGHT、HTTOP、HTTOPLEFT或HTTOPRIGHT,则将返回值更改为HTBORDER。

You can hook the wndproc and intercept the WM_WINDOWPOSCHANGING message. Not strictly WPF, but probably your best bet.

If you want to hide the resize cursors, then your best bet is to intercept WM_NCHITTEST. Call the DefWindowProc (to get the default behavior), and test the return value; if it's HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTTOP, HTTOPLEFT, or HTTOPRIGHT, change the return value to HTBORDER.

隱形的亼 2024-09-19 02:28:00

基于埃里克的回答。

示例图像

public partial class MainWindow : Window
{
    [DllImport("DwmApi.dll")]
    public static extern int DwmExtendFrameIntoClientArea(
        IntPtr hwnd,
        ref MARGINS pMarInset);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr DefWindowProc(
        IntPtr hWnd,
        int msg,
        IntPtr wParam,
        IntPtr lParam);

    private const int WM_NCHITTEST = 0x0084;
    private const int HTBORDER = 18;
    private const int HTBOTTOM = 15;
    private const int HTBOTTOMLEFT = 16;
    private const int HTBOTTOMRIGHT = 17;
    private const int HTLEFT = 10;
    private const int HTRIGHT = 11;
    private const int HTTOP = 12;
    private const int HTTOPLEFT = 13;
    private const int HTTOPRIGHT = 14;

    public MainWindow()
    {
        InitializeComponent();

        this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        try
        {
            // Obtain the window handle for WPF application
            IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
            HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
            mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);
            mainWindowSrc.AddHook(WndProc);

            // Set Margins
            MARGINS margins = new MARGINS();
            margins.cxLeftWidth = 10;
            margins.cxRightWidth = 10;
            margins.cyBottomHeight = 10;
            margins.cyTopHeight = 10;

            int hr = DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref margins);
            //
            if (hr < 0)
            {
                //DwmExtendFrameIntoClientArea Failed
            }
        }
        // If not Vista, paint background white.
        catch (DllNotFoundException)
        {
            Application.Current.MainWindow.Background = Brushes.White;
        }
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        // Override the window hit test
        // and if the cursor is over a resize border,
        // return a standard border result instead.
        if (msg == WM_NCHITTEST)
        {
            handled = true;
            var htLocation = DefWindowProc(hwnd, msg, wParam, lParam).ToInt32();
            switch (htLocation)
            {
                case HTBOTTOM:
                case HTBOTTOMLEFT:
                case HTBOTTOMRIGHT:
                case HTLEFT:
                case HTRIGHT:
                case HTTOP:
                case HTTOPLEFT:
                case HTTOPRIGHT:
                    htLocation = HTBORDER;
                    break;
            }

            return new IntPtr(htLocation);
        }

        return IntPtr.Zero;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
    public int cxLeftWidth;      // width of left border that retains its size
    public int cxRightWidth;     // width of right border that retains its size
    public int cyTopHeight;      // height of top border that retains its size
    public int cyBottomHeight;   // height of bottom border that retains its size
};

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="150" Width="200" 
    Background="Transparent"
    WindowStyle="None"
    ResizeMode="CanResize"
>
    <Grid Background="White" Margin="10,10,10,10">
        <Button Content="Go Away" Click="Button_Click" Height="20" Width="100" />
    </Grid>
</Window>

Based on Erics answer.

Example Image

public partial class MainWindow : Window
{
    [DllImport("DwmApi.dll")]
    public static extern int DwmExtendFrameIntoClientArea(
        IntPtr hwnd,
        ref MARGINS pMarInset);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr DefWindowProc(
        IntPtr hWnd,
        int msg,
        IntPtr wParam,
        IntPtr lParam);

    private const int WM_NCHITTEST = 0x0084;
    private const int HTBORDER = 18;
    private const int HTBOTTOM = 15;
    private const int HTBOTTOMLEFT = 16;
    private const int HTBOTTOMRIGHT = 17;
    private const int HTLEFT = 10;
    private const int HTRIGHT = 11;
    private const int HTTOP = 12;
    private const int HTTOPLEFT = 13;
    private const int HTTOPRIGHT = 14;

    public MainWindow()
    {
        InitializeComponent();

        this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        try
        {
            // Obtain the window handle for WPF application
            IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
            HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
            mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);
            mainWindowSrc.AddHook(WndProc);

            // Set Margins
            MARGINS margins = new MARGINS();
            margins.cxLeftWidth = 10;
            margins.cxRightWidth = 10;
            margins.cyBottomHeight = 10;
            margins.cyTopHeight = 10;

            int hr = DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref margins);
            //
            if (hr < 0)
            {
                //DwmExtendFrameIntoClientArea Failed
            }
        }
        // If not Vista, paint background white.
        catch (DllNotFoundException)
        {
            Application.Current.MainWindow.Background = Brushes.White;
        }
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        // Override the window hit test
        // and if the cursor is over a resize border,
        // return a standard border result instead.
        if (msg == WM_NCHITTEST)
        {
            handled = true;
            var htLocation = DefWindowProc(hwnd, msg, wParam, lParam).ToInt32();
            switch (htLocation)
            {
                case HTBOTTOM:
                case HTBOTTOMLEFT:
                case HTBOTTOMRIGHT:
                case HTLEFT:
                case HTRIGHT:
                case HTTOP:
                case HTTOPLEFT:
                case HTTOPRIGHT:
                    htLocation = HTBORDER;
                    break;
            }

            return new IntPtr(htLocation);
        }

        return IntPtr.Zero;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
    public int cxLeftWidth;      // width of left border that retains its size
    public int cxRightWidth;     // width of right border that retains its size
    public int cyTopHeight;      // height of top border that retains its size
    public int cyBottomHeight;   // height of bottom border that retains its size
};

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="150" Width="200" 
    Background="Transparent"
    WindowStyle="None"
    ResizeMode="CanResize"
>
    <Grid Background="White" Margin="10,10,10,10">
        <Button Content="Go Away" Click="Button_Click" Height="20" Width="100" />
    </Grid>
</Window>
乖乖公主 2024-09-19 02:28:00

一种黑客方法是设置 MinWidth/MaxWidth 和 MinHeight/MaxHeight 属性以有效地使其不可调整大小。当然,问题是您仍然会在边框上看到调整大小光标。

One hackish way to do it would be to set the MinWidth/MaxWidth and MinHeight/MaxHeight properties to effectively make it unresizeable. Of course, the problem there is you'll still get the resize cursors over the borders.

孤芳又自赏 2024-09-19 02:28:00

为什么不直接为窗口创建这个窗口边框呢?
它使用偏移量来设置窗口的颜色。
因此,一个简单的方法就是在窗口周围包裹整个边框,然后在其上获得自己的颜色!

Why don't you just create this window border for the window?
It's using an offset to set the colors of the window.
So, an easy way is just to wrap a whole border around your window and on top of that you get your own colors!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文