使用WPF shell集成库最大化时窗口超出屏幕

时间:2010-06-03 15:09:02

标签: wpf .net-4.0

我正在使用WPF Shell Integration Library创建我的wpf应用的自定义chrome。 一切都很好,但是当最大化应用时,屏幕外有6或7个像素。

这是我正在使用的代码:

<Style TargetType="{x:Type local:MainWindow}">
        <Setter Property="shell:WindowChrome.WindowChrome">
            <Setter.Value>
                <shell:WindowChrome
                    ResizeBorderThickness="6"
                    CaptionHeight="10"
                    CornerRadius="0"
                    GlassFrameThickness="1"/>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MainWindow}">
                    <Grid>
                        <Border BorderThickness="1" BorderBrush="#389FD1" Background="#389FD1">
                            <ContentPresenter Margin="0,22,0,0" Content="{TemplateBinding Content}"/>
                        </Border>
                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" >
                            <TextBlock Text="{Binding NombreUsuario}" Foreground="White" Margin="5,5,20,5" Opacity=".8" />
                            <Button Style="{StaticResource ImageButton}" Height="20" Width="20" Margin="0" Click="WindowMinimize" shell:WindowChrome.IsHitTestVisibleInChrome="True">
                                <Image Height="10" Width="10" Source="/Resources/Images/minimize.png" />
                            </Button>
                            <Button Style="{StaticResource ImageButton}" Height="20" Width="20" Margin="0" Click="WindowMaximizeRestore" shell:WindowChrome.IsHitTestVisibleInChrome="True" >
                                <Image Height="10" Width="10" Source="/Resources/Images/maximize.png" />
                            </Button>
                            <Button Style="{StaticResource ImageButton}" Height="20" Width="20" Margin="0" Click="WindowClose" shell:WindowChrome.IsHitTestVisibleInChrome="True">
                                <Image Height="10" Width="10" Source="/Resources/Images/close.png" />
                            </Button>
                        </StackPanel>

                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

7 个答案:

答案 0 :(得分:46)

Windows最大化时会裁剪窗口边缘,以遮挡通常调整大小的边缘。您可以通过在窗口和内容之间放置代理边框来解决此问题,然后在最大化时增加厚度。

我修改了lib附带的示例来执行此操作,可以对您的示例进行相同的基本更改:

<ControlTemplate TargetType="{x:Type local:SelectableChromeWindow}">
  <Border BorderBrush="Green">
    <Border.Style>
      <Style TargetType="{x:Type Border}">
        <Setter Property="BorderThickness" Value="0"/>
        <Style.Triggers>
          <DataTrigger Binding="{Binding ElementName=ThisWindow, Path=WindowState}" Value="Maximized">
            <Setter Property="BorderThickness" Value="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowResizeBorderThickness}"/>
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </Border.Style>
    <Grid [...]/>
  </Border>
</ControlTemplate>

我希望有所帮助。

对于.net 4.5及以上版本, SystemParameters略有不同,例如:

<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}, Path=WindowState}" Value="Maximized">
    <Setter Property="BorderThickness" Value="{Binding Source={x:Static SystemParameters.WindowResizeBorderThickness}}"/>
</DataTrigger>

答案 1 :(得分:7)

这对我有用:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=Microsoft.Windows.Shell"
                xmlns:Views="clr-namespace:BorderLessWpf.Views">

<Style TargetType="{x:Type Views:ShellView}" >
    <Setter Property="shell:WindowChrome.WindowChrome">
        <Setter.Value>
            <shell:WindowChrome
                ResizeBorderThickness="6"
                CaptionHeight="10"
                CornerRadius="0"
                GlassFrameThickness="1"/>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="WindowState" Value="Maximized">
            <Setter Property="BorderThickness" Value="6" />
        </Trigger>
    </Style.Triggers>
</Style>

答案 2 :(得分:2)

要解决窗口离开屏幕的问题,只需设置:

this.ResizeMode = System.Windows.ResizeMode.NoResize;

参见JAPF's "Set up the main window of your WPF project" post 了解更多信息。

答案 3 :(得分:2)

在我的项目中,我将CaptionHeight设置为0,将ResizeMode设置为CanResizeWithGrip。这是我提出的适当厚度的代码。

            Thickness maximizeFix = new Thickness(SystemParameters.WindowNonClientFrameThickness.Left +
                SystemParameters.WindowResizeBorderThickness.Left,
                SystemParameters.WindowNonClientFrameThickness.Top +
                SystemParameters.WindowResizeBorderThickness.Top
                - SystemParameters.CaptionHeight,
                SystemParameters.WindowNonClientFrameThickness.Right +
                SystemParameters.WindowResizeBorderThickness.Right,
                SystemParameters.WindowNonClientFrameThickness.Bottom +
                SystemParameters.WindowResizeBorderThickness.Bottom);

我将使用像Joe Castro那样的边框,然后将厚度绑定到我在窗口状态发生变化时更新的属性。

代码似乎很笨拙,但我还没有找到另一种解决方案。

答案 4 :(得分:2)

为什么会这样?

Raymond Chen在他的笔记Why are the dimensions of a maximized window larger than the monitor?中对此进行了解释:

挂在屏幕上的多余八个像素是窗口 边界。当您最大化窗口时,窗口管理器会安排 东西,以便窗口的客户区填充您的宽度 工作区,它加上标题栏填充了工作区的高度 区。毕竟,您希望看到尽可能多的文档。 无需向您显示不适合您的窗口边框 任何好处。 (它将标题栏留在屏幕上 原因。)

如何处理?

@Joe Castro提出了正确的方法。基本上,每次最大化时,您都必须在窗口周围添加边框(或指定边距)。并且SystemParameters.WindowResizeBorderThickness也是正确的属性,但是... 它有一个错误

对我来说,它会为{%{1}}而不是正确的4px边框(100%的显示比例(可以在8px中进行更改)和大约Display Settings而不是正确的{{ 1}}代表175%。

为什么我确定这是一个错误,而不仅仅是错误的属性?

内部3px使用GetSystemMetrics调用来获取边框的设备像素。它查询7pxSystemParameters.WindowResizeBorderThickness索引,然后将其转换为逻辑像素。

现在检查此old bug report

采用以下代码行:

CXFRAME (32)

使用Visual Studio 2010编译时,在我的Windows7计算机上, 产生:cx == 9,cy == 9和cp == 27。

如果我使用Vision Studio 2012 RC在相同的代码上编译完全相同的代码 机器,结果是:cx == 5,cy == 5和cp == 27。

答案:

Microsoft于2012年7月12日上午11:03发布 感谢您提交错误。您报告的问题似乎是Windows问题,并且 我们已将错误转发给他们。

但是这个问题有一些好消息:GetSystemMetrics() returns different results for .NET 4.5 & .NET 4.0

对于.NET 4.5和更高版本,您只需将CYFRAME(33)值添加到 int cx = ::GetSystemMetrics(SM_CXSIZEFRAME); int cy = ::GetSystemMetrics(SM_CYSIZEFRAME); int cp = ::GetSystemMetrics(SM_CYCAPTION); SM_CXPADDEDBORDER (92)即可获得正确的值。

最终的解决方案是什么?

使用@Joe Castro方法,但具有固定属性:

CXFRAME (32)

答案 5 :(得分:1)

here开始,我想我会尝试设置WindowChrome.NonClientFrameEdges

通过一些实验,结果证明,您可以通过在最大化时将其设置为NonClientFrameEdges.Bottom并在未最大化时将其设置为NonClientFrameEdges.None来获得所需效果。

这使得边距除了底部之外的所有边都消失,但关键是导致任务栏下的重叠不再发生。

将WindowChrome设置为之前到WindowState是很重要的,所以在我的代码隐藏中我有函数(MainGrid2保存禁止状态栏的所有窗口内容,并且StatusGrid保持状态巴):

    private void Maximise()
    {
        StatusGrid.Margin = new Thickness(7, 0, 7, 0);
        MainGrid2.Margin = new Thickness(12, 12, 12, 0);            
        chrome.NonClientFrameEdges = NonClientFrameEdges.Bottom;
        WindowChrome.SetWindowChrome(this, chrome); 
        WindowState = System.Windows.WindowState.Maximized;
    }

    private void Restore()
    {
        StatusGrid.Margin = new Thickness(0);
        MainGrid2.Margin = new Thickness(5, 5, 5, 0);
        chrome.NonClientFrameEdges = NonClientFrameEdges.None;
        WindowChrome.SetWindowChrome(this, chrome);
        WindowState = System.Windows.WindowState.Normal;
    }

答案 6 :(得分:0)

我设法通过在窗口的主要内容周围添加边框并将其绑定到ViewModel中的属性来解决该问题。当用户按下最大化按钮时,将触发一个命令,该命令将BorderThickness设置为7。再次按下最大化按钮时,BorderThickness被设置为0。

    <!-- Content of my window -->
    <Border BorderThickness="{Binding BorderThickness}" BorderBrush="{StaticResource OffsetBlackBrush}">
            <Grid>
<StackPanel Grid.Column="2" Orientation="Horizontal">
                    <Button Content="-" Command="{Binding MinimizeCommand}" Style="{StaticResource WindowControlButton}" />
                    <Button Content="[ ]" Command="{Binding MaximizeCommand}" Style="{StaticResource WindowControlButton}" />
                    <Button Content="X" Command="{Binding CloseCommand}" Style="{StaticResource WindowCloseButton}" />
                </StackPanel>
            </Grid>
    </Border>


<!-- BorderThickness property in VM -->
public int BorderThickness { get; set; } = 0;


    /// <summary>
    /// Maximizes the current window
    /// </summary>
    public RelayCommand MaximizeCommand
    {
        get => new RelayCommand(param =>
        {
            if (!_view.GetWindowState())
            {
                BorderThickness = 7;
                _view.SetWindowState("Maximize"); // Change window state to maximized using interface passed into ctor
            }
            else
            {
                BorderThickness = 0;
                _view.SetWindowState("Normal");
            }
        });
    }