我正在查看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关闭时仍然相同。
答案 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,它简单地将窗口第一个视觉元素的边距重置为新的厚度实例,从而擦除您的自定义按样式、模板等进行设置
解决方法可以是: