wpf - 实现为 CustomControl 的 WPF 窗口在设计时不应用模板
问题描述
我正在尝试将 WPF 窗口实现为 CustomControl,以便我可以覆盖默认的 WindowChrome 并在一组应用程序中创建自己的可重用外观。我有一个正在运行的演示项目,它将在运行时自动将自定义控件样式模板应用于窗口,但在设计时很难让它干净地工作。
我意识到这是WPF 自定义窗口在设计时不应用其通用模板的副本,但是对于我的用例,该问题没有适用的答案。我的演示将所有内容都放在同一个项目中,因此不匹配目标 cpu 没有问题。而且我必须重新设置窗口的样式,所以仅仅替换内容控制部分也不起作用。
这是我的基本窗口类 (Classes\WindowBase.cs),带有用于测试的附加依赖项属性:
using System.Windows;
namespace WPFTestWindowSubclassing.Classes
{
public class WindowBase : Window
{
public string ContentText
{
get { return (string)GetValue(ContentTextProperty); }
set { SetValue(ContentTextProperty, value); }
}
public static readonly DependencyProperty ContentTextProperty =
DependencyProperty.Register(
"ContentText",
typeof(string),
typeof(WindowBase),
new PropertyMetadata(string.Empty));
}
}
还有我的 CustomControl 窗口类(CustomContorls\CustomWindow.cs):
using System.Windows;
using System.Windows.Controls;
using WPFTestWindowSubclassing.Classes;
namespace WPFTestWindowSubclassing.CustomControls
{
[TemplatePart(Name = "PART_CloseButton", Type = typeof(Button))]
public class CustomWindow : WindowBase
{
static CustomWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(CustomWindow),
new FrameworkPropertyMetadata(typeof(CustomWindow)));
}
public override void OnApplyTemplate()
{
((Button)GetTemplateChild("PART_CloseButton")).Click += (s, e) => this.Close();
ContentText += " Internal Template Applied.";
base.OnApplyTemplate();
}
}
}
窗口的样式资源 (ResourceDictionaries\CustomControls\CustomWindowStyle.xaml):
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:WPFTestWindowSubclassing.CustomControls">
<Style
x:Key="{x:Type cc:CustomWindow}"
TargetType="{x:Type cc:CustomWindow}">
<Setter Property="Background" Value="AliceBlue" />
<Setter Property="AllowsTransparency" Value="True" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome
CaptionHeight="30"
CornerRadius="0"
GlassFrameThickness="0"
NonClientFrameEdges="None"
ResizeBorderThickness="10"
UseAeroCaptionButtons="False" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type cc:CustomWindow}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Button
x:Name="PART_CloseButton"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Height="30" Width="30"
WindowChrome.IsHitTestVisibleInChrome="True"/>
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
我的主题\Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="../ResourceDictionaries/CustomControls/CustomWindowStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
最后,我的 MainWindow.xaml 和 MainWindow.xaml.cs:
<cc:CustomWindow
x:Class="WPFTestWindowSubclassing.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:cc="clr-namespace:WPFTestWindowSubclassing.CustomControls"
mc:Ignorable="d"
Title="MainWindow"
Height="300"
Width="400"
ContentText="Hello?"
Loaded="Window_Loaded">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type cc:CustomWindow}}, Path=ContentText}"
Grid.RowSpan="2" />
</Grid>
</cc:CustomWindow>
using System.Windows;
using WPFTestWindowSubclassing.CustomControls;
namespace WPFTestWindowSubclassing
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : CustomWindow
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ContentText += " Window Loaded!";
}
public override void OnApplyTemplate()
{
ContentText += " Template Applied!";
base.OnApplyTemplate();
}
}
}
这不是一个完整的漂亮风格实现,但足以重现该问题。当我运行项目时,这一切都有效。窗口是无框的,调整大小手柄仍然有效,关闭按钮有效。但在 Visual Studio XAML 设计器中,它看起来仍然像一个常规窗口。我可以通过手动将样式应用于窗口来强制它工作:
<cc:CustomWindow
...
Style="{StaticResource {x:Type cc:CustomWindow}}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="ResourceDictionaries/CustomControls/CustomWindowStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
...
但是为什么在运行时需要这种额外的直接样式分配呢?有没有更简单的方法让 Window 在设计时像任何其他 CustomControl 实现一样“正常工作”?
我从一个类似的问题中遇到了这个答案(https://stackoverflow.com/a/59297503/1236614),这似乎表明 VS XAML 设计器在显示一个窗口时正在做一些奇怪的幕后废话,但是那真的是怎么回事?这也可以解释为什么绑定到窗口的 Title 或我的 CustomWindow 的 ContentText 属性在设计时也不起作用 - 设计时的祖先可能不是真正的“窗口”。一定有办法解决这个问题,对吧?
解决方案
推荐阅读
- php - 其他会话正在工作时不显示会话消息
- html - 十六进制代码不适用于 HTML 中的小于“<”符号,除非它旁边有空格
- google-cloud-platform - 如何通过 java SDK 在 GCP 中创建项目?
- git - GitHub 更改第一个推送的提交消息
- html - 为什么背景位置属性在这里不起作用
- python - 在 Python 中使用新数组的插入算法
- python - 熊猫条件
- xml - 搜索单个标点字符(全文索引 basex)
- javascript - 菜单中的 css 不起作用,因为 id 被推入了错误的容器中
- python-3.x - Drive API 404 在文件夹内创建文件