【问题标题】:How to create a WPF Window without a border that can be resized via a grip only?如何创建一个没有边框的WPF窗口,只能通过手柄调整大小?
【发布时间】:2010-10-11 07:27:08
【问题描述】:

如果您在 WPF Window 上设置 ResizeMode="CanResizeWithGrip",则右下角会显示调整大小的夹点,如下所示:

如果您也设置了WindowStyle="None",标题栏会消失,但灰色斜边仍然存在,直到您设置ResizeMode="NoResize"。不幸的是,设置了这种属性组合后,调整大小的夹点也消失了。

我已经通过自定义Style 覆盖了Window 的ControlTemplate。我想自己指定窗口的边框,我不需要用户能够从所有四个侧面调整窗口的大小,但我确实需要一个调整大小的手柄。

有人可以详细说明满足所有这些标准的简单方法吗?

  1. 不要在Window 上设置边框,除了我在ControlTemplate 中指定的边框。
  2. 是否在右下角有一个有效的调整大小手柄。
  3. 没有标题栏。

【问题讨论】:

标签: .net wpf window controltemplate resizegrip


【解决方案1】:

我很难通过@fernando-aguirre 使用WindowChrome 获得答案。在我的情况下它不起作用,因为我在 MainWindow 中覆盖了 OnSourceInitialized 而没有调用基类方法。

protected override void OnSourceInitialized(EventArgs e)
{
    ViewModel.Initialize(this);
    base.OnSourceInitialized(e); // <== Need to call this!
}

这让我困惑了很长时间。

【讨论】:

    【解决方案2】:

    如果您在Window 上设置AllowsTransparency 属性(即使没有设置任何透明度值),边框也会消失,您只能通过夹点调整大小。

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="640" Height="480" 
        WindowStyle="None"
        AllowsTransparency="True"
        ResizeMode="CanResizeWithGrip">
    
        <!-- Content -->
    
    </Window>
    

    结果如下:

    【讨论】:

    • 纯属侥幸我知道这一点 - 今天下午我正在使用相同的控制装置。 :)
    • 哇,我没想到会这样,但它非常适合在 5 分钟内制作自己的便笺,谢谢 :)
    • AllowTransparency 有几个缺点,但 Windows 不能再托管 WebBrowser 等子窗口控件,通常强制软件渲染,报告内存泄漏。请参阅下面的解决方法。
    • 您只需要 WindowStyle="None" 即可摆脱边框; AllowsTransparency 只是碰巧需要它,但不影响边框..
    • @Grault 去掉了窗口标题,但表单周围仍然有一个实心边框。 AllowsTransparency 摆脱了边界。
    【解决方案3】:

    我试图用WindowStyle="None" 创建一个无边框窗口,但是当我测试它时,顶部似乎出现了一个白条,经过一些研究,它似乎是“调整边框大小”,这是一张图片(我黄色标注):

    在互联网上进行了一些研究,以及许多困难的非 xaml 解决方案后,我发现的所有解决方案都是 C# 中的代码和大量代码行,我在这里间接找到了解决方案:Maximum custom window loses drop shadow effect

    <WindowChrome.WindowChrome>
        <WindowChrome 
            CaptionHeight="0"
            ResizeBorderThickness="5" />
    </WindowChrome.WindowChrome>
    

    注意 :您需要使用 .NET 4.5 框架,或者如果您使用的是旧版本使用 WPFShell,只需引用 shell 并改用 Shell:WindowChrome.WindowChrome。

    我使用了Window的WindowChrome属性,如果你使用这个,白色的“调整大小边框”就会消失,但是你需要定义一些属性才能正常工作。

    CaptionHeight: 这是标题区域(标题栏)的高度,允许 Aero 捕捉、双击行为,就像普通标题栏一样。将此设置为 0(零)以使按钮起作用。

    ResizeBorderThickness: 这是窗口边缘的厚度,您可以在此处调整窗口大小。我设置为 5 是因为我喜欢这个数字,而且如果设置为零,则很难调整窗口大小。

    使用此短代码后,结果如下:

    现在,没有使用ResizeMode="NoResize" 和AllowsTransparency="True",白色边框消失了,并且在窗口中显示了阴影。

    稍后我将解释如何使用简单而简短的代码轻松制作按钮(我没有为按钮使用图像),我是新手,我认为我可以发布到 codeproject,因为在这里我没有找到发布教程的地方。

    也许还有另一种解决方案(我知道对于像我这样的菜鸟来说有困难和困难的解决方案)但这适用于我的个人项目。

    这是完整的代码

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Concursos"
        mc:Ignorable="d"
        Title="Concuros" Height="350" Width="525"
        WindowStyle="None"
        WindowState="Normal" 
        ResizeMode="CanResize"
        >
    <WindowChrome.WindowChrome>
        <WindowChrome 
            CaptionHeight="0"
            ResizeBorderThickness="5" />
    </WindowChrome.WindowChrome>
    
        <Grid>
    
        <Rectangle Fill="#D53736" HorizontalAlignment="Stretch" Height="35" VerticalAlignment="Top" PreviewMouseDown="Rectangle_PreviewMouseDown" />
        <Button x:Name="Btnclose" Content="r" HorizontalAlignment="Right" VerticalAlignment="Top" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>
        <Button x:Name="Btnmax" Content="2" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,35,0" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>
        <Button x:Name="Btnmin" Content="0" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,70,0" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>
    
    </Grid>
    

    谢谢!

    【讨论】:

    • 好吧,感谢这个!这是迄今为止该线程最简单/不折衷的答案!应该得到更多的“赞成”票。我不得不承认,我对此有点悲观,尤其是对幕后发生的事情。我什至检查了 WFP 树,它确实看起来没有添加回透明度。甚至像“WebBrowser”这样棘手的控件也能正常显示。当应用程序承受很大压力时,我遇到了使用透明度的渲染冻结问题......好吧,这个解决方案不会发生这种情况。我认为可能是时候退出 @Wobbles 解决方案了!
    • 如果我正确解释 Rectangle_PreviewMouseDown 事件的使用,看起来这可能仍需要互操作以进行窗口拖动。
    • 这可能在
    • 嗨@FernandoAguirre,我发布了this related question,如果您有答案,将不胜感激。
    • 迄今为止最好的答案!正是需要做什么。没有权衡,没有互操作的黑客攻击。谢谢。
    【解决方案4】:

    虽然公认的答案非常正确,但只想指出 AllowTransparency 有一些缺点。它不允许显示子窗口控件,即 WebBrowser,并且通常会强制软件渲染,这可能会对性能产生负面影响。

    不过有更好的解决方法。

    当您想要创建一个没有边框且可调整大小且能够承载 WebBrowser 控件或指向您根本无法访问的 URL 的 Frame 控件的窗口时,所述控件的内容将显示为空。

    我找到了一个解决方法;在窗口中,如果您将 WindowStyle 设置为 None,将 ResizeMode 设置为 NoResize(请耐心等待,完成后您仍然可以调整大小)然后确保您有 UNCHECKED AllowsTransparency 您将拥有一个没有边框的静态大小的窗口并显示浏览器控件。

    现在,您可能仍然希望能够调整大小,对吧?好吧,我们可以通过互操作调用来做到这一点:

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    
        [DllImportAttribute("user32.dll")]
        public static extern bool ReleaseCapture();
    
        //Attach this to the MouseDown event of your drag control to move the window in place of the title bar
        private void WindowDrag(object sender, MouseButtonEventArgs e) // MouseDown
        {
            ReleaseCapture();
            SendMessage(new WindowInteropHelper(this).Handle,
                0xA1, (IntPtr)0x2, (IntPtr)0);
        }
    
        //Attach this to the PreviewMousLeftButtonDown event of the grip control in the lower right corner of the form to resize the window
        private void WindowResize(object sender, MouseButtonEventArgs e) //PreviewMousLeftButtonDown
        {
            HwndSource hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
            SendMessage(hwndSource.Handle, 0x112, (IntPtr)61448, IntPtr.Zero);
        }
    

    瞧,一个没有边框的 WPF 窗口,仍然可以移动和调整大小,而不会失去与 WebBrowser 等控件的兼容性

    【讨论】:

    • 如果我们想从各个方面调整大小,而不仅仅是右下角,但仍然希望没有可见的边框,我们应该怎么做?
    • 这里是其他 wParam 值,只需根据需要使用这些将新事件分配给新 UI 对象private enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
    • 这对我很有用,但有一个例外,但一旦你拥有 NoResize,你就不能再通过将它拖到顶部来捕捉窗口了。
    • @CJK 没错,但毫无疑问,您也可以为此挂钩并处理 Windows 消息。
    • 我无法拖动窗口。知道为什么吗? (调整大小就像一个魅力)
    【解决方案5】:

    示例:

    <Style TargetType="Window" x:Key="DialogWindow">
            <Setter Property="AllowsTransparency" Value="True"/>
            <Setter Property="WindowStyle" Value="None"/>
            <Setter Property="ResizeMode" Value="CanResizeWithGrip"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Window}">
                        <Border BorderBrush="Black" BorderThickness="3" CornerRadius="10" Height="{TemplateBinding Height}"
                                Width="{TemplateBinding Width}" Background="Gray">
                            <DockPanel>
                                <Grid DockPanel.Dock="Top">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition></ColumnDefinition>
                                        <ColumnDefinition Width="50"/>
                                    </Grid.ColumnDefinitions>
                                    <Label Height="35" Grid.ColumnSpan="2"
                                           x:Name="PART_WindowHeader"                                            
                                           HorizontalAlignment="Stretch" 
                                           VerticalAlignment="Stretch"/>
                                    <Button Width="15" Height="15" Content="x" Grid.Column="1" x:Name="PART_CloseButton"/>
                                </Grid>
                                <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                                            Background="LightBlue" CornerRadius="0,0,10,10" 
                                            Grid.ColumnSpan="2"
                                            Grid.RowSpan="2">
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition/>
                                            <ColumnDefinition Width="20"/>
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="*"/>
                                            <RowDefinition Height="20"></RowDefinition>
                                        </Grid.RowDefinitions>
                                        <ResizeGrip Width="10" Height="10" Grid.Column="1" VerticalAlignment="Bottom" Grid.Row="1"/>
                                    </Grid>
                                </Border>
                            </DockPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    【讨论】:

    • 您应该简要说明代码的工作原理。
    猜你喜欢
    • 2012-11-22
    • 2013-07-12
    • 2011-09-22
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    相关资源
    最近更新 更多