窗口模板中的边框边距与WindowChrome一起使用时没有任何效果

时间:2013-05-17 12:59:25

标签: c# wpf xaml windows-shell window-chrome

我正在查看WindowChrome库中的System.Windows.Shell课程(v 3.5.41019.1)。当我尝试创建Window模板时,模板中Border元素的边距似乎没有效果:

<Window x:Class="WpfApplication7.MainWindow"
        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"
        Title="MainWindow" Height="350" Width="525" Style="{DynamicResource WindowStyle1}">
    <Window.Resources>
        <Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
<!-- Here is the WindowChrome.-->
            <Setter Property="shell:WindowChrome.WindowChrome">
                <Setter.Value>
                    <shell:WindowChrome />
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Window}">
<!-- And here is the Border. Its margin has no effect as far as I can tell.-->
                        <Border Margin="25" Background="Red">
                            <AdornerDecorator>
                                <ContentPresenter/>
                            </AdornerDecorator>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>

    </Grid>
</Window>

您认为原因是什么?我想知道,因为我看到有些人使用类似*:

的东西
<Border x:Name="WindowBorder" Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowNonClientFrameThickness}" Background="Red">

但由于它在我的测试中没有任何影响,这可能是什么意思呢?

(*)其中一个地方是ModernUI上的CodePlex项目。

修改:我已在Windows 7上使用Aero对此进行了测试。

编辑2:它与Aero关闭时仍然相同。

3 个答案:

答案 0 :(得分:8)

根据MSDN,WindowChrome

  

表示描述窗口的非客户区域的自定义的对象。

在阅读MSDN示例并播放您的代码一段时间后,我注意到您的代码应该类似于以下MSDN示例代码:

<Style x:Key="StandardStyle" TargetType="{x:Type local:MainWindow}">
<Setter Property="shell:WindowChrome.WindowChrome">
    <Setter.Value>
        <shell:WindowChrome />
    </Setter.Value>
</Setter>
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:MainWindow}">
            <!--Note there is a Grid as the root-->
            <Grid>
                <Border Background="White"
                        Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowNonClientFrameThickness}">
                    <ContentPresenter Content="{TemplateBinding Content}" />
                </Border>
                <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" 
                           VerticalAlignment="Top" HorizontalAlignment="Left" 
                           Margin="36,8,0,0"/>
                <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}"
                       VerticalAlignment="Top" HorizontalAlignment="Left"
                       Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}" 
                       Width="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=SmallIconSize.Width}"
                       shell:WindowChrome.IsHitTestVisibleInChrome="True"/>
            </Grid>
        </ControlTemplate>
    </Setter.Value>
</Setter>

注意,有一个Grid作为根元素,它包含一些用于自定义窗口NC的元素。

<强>更新

您可能会在MSDN页面的注释中注意到它包含以下部分:

WindowStyle.None

WindowChrome

这两种自定义WPF应用程序窗口外观的方法。

但是,将Window.WindowStyle属性设置为WindowStyle.None

  

这会从窗口中删除非客户端框架,只留下   客户区,您可以应用自定义样式。但是,当   删除非客户端框架,您也失去了系统功能   它提供的行为,如标题按钮和窗口   大小调整。另一个副作用是窗户将覆盖   Windows任务栏最大化时。

然后引入WindowChrome以使用WPF启用NC自定义:

  

要在保留其标准功能的同时自定义窗口,您   可以使用WindowChrome类。 WindowChrome类将它分开   视觉效果的窗框功能,让你   控制你的客户和非客户区域之间的边界   应用程序窗口WindowChrome类允许您放入WPF内容   窗框通过扩展客户区覆盖非客户端   区域。同时,它通过两个保留系统行为   无形区域;调整边框和标题区域。

回到你的问题,你找到的模板应该从MSDN示例代码中复制,但是错过了真正的根Grid。 边界边缘是为NC提供一些空间。 在MSDN示例代码中,ContenPreseter仅包含客户端区域,而NC包含Border,窗口标题为TextBlock,窗口图标为Image

总结一下,通过设置WindowChrome,您可以在Window.Template中自定义窗口的NC区域。

注意: 示例MSDN示例代码在.Net 4.5中看起来有点过时,System.Windows.Shell.WindowChrome现在位于PresentationFramework.dll中,因此代码可能如下所示:

<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="350" Width="525" Style="{DynamicResource WindowStyle1}" Icon="Icon1.ico">
<Window.Resources>
    <Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome />
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                        <Border Background="Red"
                        Margin="{Binding Source={x:Static SystemParameters.WindowNonClientFrameThickness}}">
                            <ContentPresenter Content="{TemplateBinding Content}" />
                        </Border>
                        <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" 
                           VerticalAlignment="Top" HorizontalAlignment="Left" 
                           Margin="36,8,0,0"/>
                        <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}"
                       VerticalAlignment="Top" HorizontalAlignment="Left"
                       Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=WindowChrome.WindowChrome.ResizeBorderThickness}" 
                       Width="{Binding Source={x:Static SystemParameters.SmallIconWidth}}"
                       WindowChrome.IsHitTestVisibleInChrome="True"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <Button />
</Grid>

答案 1 :(得分:1)

我认为你试图设置边界的方式存在一些误解。以下是msdn

中提供的WindowChrome类的说明
  

WindowChrome类将窗口框架的功能与视觉效果分开,并允许您控制应用程序窗口的客户端和非客户端区域之间的边界。 WindowChrome类允许您通过扩展客户区覆盖非客户区来将WPF内容放在窗口框架中。同时,它通过两个不可见的区域保留系统行为;调整边框和标题区域。

因此,如果您尝试自定义窗口的NonClient区域,那么不应该将Border设置为Border Presenter。那是客户区。相反,在模板中,您可以添加除Content Presenter之外的XAML来定义NonClient区域。我刚刚尝试了一个基于代码的简单代码,它将窗口的标题属性向右移动了100个值。这是代码。

<Window x:Class="WPF_ToggleButton.ShellWindow"
    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"
    Title="MainWindow" Height="350" Width="525" Style="{DynamicResource WindowStyle1}" 
    >

<Window.Resources>
    <Style x:Key="WindowStyle1" TargetType="{x:Type Window}">
        <Setter Property="shell:WindowChrome.WindowChrome">
            <Setter.Value>
                <shell:WindowChrome />
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                        <Border Background="Yellow">
                            <AdornerDecorator>
                                <ContentPresenter Content="{TemplateBinding Content}"/>
                            </AdornerDecorator>
                        </Border>
                        <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" 
                           VerticalAlignment="Top" HorizontalAlignment="Left" 
                           Margin="100,0,0,0"/>
                    </Grid>                        
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <Border Margin="50" Background="AliceBlue"/>
</Grid>

因此,您可以使用XAML代码在NonClient区域中拥有任何元素,例如代表窗口关闭按钮等的图像。窗口中的最后一个元素定义了在模板

中传递给Content Presenter的客户区。

简而言之,如果您不想使用Content Presenter自定义Client Area,而如果您有兴趣更改NonBient Area(如标题栏显示),请关闭图像图标,然后在模板中定义它。

一个短暂的观察。我认为Margin对于Window来说没有任何意义。尝试将其设置为普通窗口,我认为它不会尊重它。

答案 2 :(得分:0)

遇到同样的问题。无论我如何尝试在 MainWindow 的 ControlTemplate 中设置根元素的 Margin(其类型无关紧要),启动应用程序时它始终为 0。答案(感谢 ILSpy)在 WindowChrome 实现中。

当 WindowChrome 附加到一个窗口时,它正在应用 Chrome 功能,除其他外,它执行一个方法 WindowChromWorker._FixupTemplateIssues,它简单地将窗口第一个视觉元素的边距重置为新的厚度实例,从而擦除您的自定义按样式、模板等进行设置

解决方法可以是:

  • 将您的模板嵌入到一个新的、无外观的根元素中,例如一个网格,所以你的原始根的边距不会被覆盖
  • 调整根的填充