使用WPF外壳集成库最大化时的屏幕外窗口

使用WPF外壳集成库最大化时的屏幕外窗口,wpf,.net-4.0,Wpf,.net 4.0,我正在使用创建wpf应用程序的自定义chrome。 一切都很好,但当最大化应用程序时,屏幕上会出现6或7个像素 这是我正在使用的代码: <Style TargetType="{x:Type local:MainWindow}"> <Setter Property="shell:WindowChrome.WindowChrome"> <Setter.Value> <shell:Wind

我正在使用创建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>

当窗口最大化时,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及以上版本,系统参数略有不同,例如:

<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>

这对我很有用:

<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>

从,我想我应该尝试设置
WindowChrome.nonClient框架边缘

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

这会使除底部以外的所有边上的边距消失,但关键是不会再发生任务栏下的重叠

WindowChrome设置在WindowsState之前是很重要的,因此在我的代码中,我具有以下功能(MainGrid2保存状态栏之外的所有窗口内容,StatusGrid保存状态栏):


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

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

有关详细信息。

在我的项目中,我将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所做的边界,然后将厚度绑定到一个属性,当窗口状态改变时,我将更新该属性


代码看起来很僵硬,但我还没有找到其他解决方案。

我通过在窗口的主要内容周围添加边框并绑定到ViewModel中的属性,成功地解决了这个问题。当用户按下最大化按钮时,将触发一个命令,将边界厚度设置为7。再次按下“最大化”按钮时,边界厚度设置为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");
            }
        });
    }

公共int边界厚度{get;set;}=0;
/// 
///最大化当前窗口
/// 
公共关系社区最大化命令
{
get=>new RelayCommand(参数=>
{
如果(!\u view.getWindowsState())
{
边界厚度=7;
_view.setWindowsState(“Maximize”);//使用传递到ctor的接口将窗口状态更改为maximized
}
其他的
{
边界厚度=0;
_view.setWindowsState(“正常”);
}
});
}
为什么会发生这种情况? 他在便条中解释了这一点:

屏幕上额外悬挂的八个像素是窗口 边界。最大化窗口时,窗口管理器会进行排列 使窗口的客户端区域填充窗口的宽度 工作区,它加上标题栏填充工作的高度 地区毕竟,您希望看到尽可能多的文档; 没有必要向您显示不适合您的窗口边框 好的。(它将标题栏保留在屏幕上以便于查看。) 原因。)

如何处理? @乔·卡斯特罗提出了正确的方法。每次窗口最大化时,基本上必须在其周围添加边框(或指定边距)。和
SystemParameters.WindowResizeByOrderThickness
也是正确的属性,但是它有一个bug

对于我来说,对于100%的显示比例(可以在显示设置中更改),它给出了
4px
边框,而不是正确的
8px
,对于175%的显示比例,它给出了大约
3px
,而不是正确的
7px

为什么我这么肯定这是一个bug而不仅仅是错误的属性? 内部
SystemParameters.WindowResizeByOrderThickness
使用调用获取设备边框像素。它查询
CXFRAME(32)
CYFRAME(33)
索引,然后将其转换为逻辑像素

现在检查一下:

以以下代码行为例:

    int cx = ::GetSystemMetrics(SM_CXSIZEFRAME);
    int cy = ::GetSystemMetrics(SM_CYSIZEFRAME);
    int cp = ::GetSystemMetrics(SM_CYCAPTION);
使用Visual Studio 2010编译时,在我的Windows7计算机上 收益率:cx==9,cy==9,cp==27

如果我在同一平台上使用VisionStudio2012 RC编译相同的代码 这将产生:cx==5、cy==5和cp==27

答案是:

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

但这个问题带来了一些好消息:

对于.NET 4.5及更高版本,您只需将
SM\u CXPADDEDBORDER(92)
值添加到
CXFRAME(32)
CYFRAME(33)
,即可获得正确的值

    int cx = ::GetSystemMetrics(SM_CXSIZEFRAME);
    int cy = ::GetSystemMetrics(SM_CYSIZEFRAME);
    int cp = ::GetSystemMetrics(SM_CYCAPTION);
public static class SystemParametersFix
{
    public static Thickness WindowResizeBorderThickness
    {
        get
        {
            float dpix = GetDpi(GetDeviceCapsIndex.LOGPIXELSX);
            float dpiy = GetDpi(GetDeviceCapsIndex.LOGPIXELSY);

            int dx = GetSystemMetrics(GetSystemMetricsIndex.CXFRAME);
            int dy = GetSystemMetrics(GetSystemMetricsIndex.CYFRAME);

            // this adjustment is needed only since .NET 4.5 
            int d = GetSystemMetrics(GetSystemMetricsIndex.SM_CXPADDEDBORDER);
            dx += d;
            dy += d;

            var leftBorder = dx / dpix;
            var topBorder = dy / dpiy;

            return new Thickness(leftBorder, topBorder, leftBorder, topBorder);
        }
    }

    [DllImport("user32.dll")]
    private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("user32.dll")]
    private static extern IntPtr GetDC(IntPtr hwnd);

    [DllImport("gdi32.dll")]
    private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

    private static float GetDpi(GetDeviceCapsIndex index)
    {
        IntPtr desktopWnd = IntPtr.Zero;
        IntPtr dc = GetDC(desktopWnd);
        float dpi;
        try
        {
            dpi = GetDeviceCaps(dc, (int)index);
        }
        finally
        {
            ReleaseDC(desktopWnd, dc);
        }
        return dpi / 96f;
    }

    private enum GetDeviceCapsIndex
    {
        LOGPIXELSX = 88,
        LOGPIXELSY = 90
    }

    [DllImport("user32.dll")]
    private static extern int GetSystemMetrics(GetSystemMetricsIndex nIndex);

    private enum GetSystemMetricsIndex
    {
        CXFRAME = 32,
        CYFRAME = 33,
        SM_CXPADDEDBORDER = 92
    }
}