作为 CustomControl 实现的 WPF 窗口在设计时不应用模板

问题描述

我正在尝试将 WPF 窗口实现为 CustomControl,以便我可以覆盖默认的 WindowChrome 并在一套应用程序中创建我自己的可重用外观。我有一个正在运行的演示项目,它将在运行时自动将自定义控件样式模板应用到窗口,但我很难让它在设计时正常工作。

我意识到这是 WPF custom window does not apply its generic template at design time 的副本,但没有适用于我的用例的问题的适用答案。我的演示在同一个项目中包含所有内容,因此目标 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 设计器中,它看起来仍然像一个常规窗口。我可以通过手动将样式应用到 Window 来强制它工作:

<cc:CustomWindow
    ...
    Style="{StaticResource {x:Type cc:CustomWindow}}">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary
                    Source="ResourceDictionaries/CustomControls/CustomWindowStyle.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    ...

但是为什么在运行时需要这种额外的直接样式分配?有没有更简单的方法让窗口在设计时像任何其他 CustomControl 实现一样“正常工作”?

我从一个类似的问题中找到了这个答案 (https://stackoverflow.com/a/59297503/1236614),该问题似乎表明 VS XAML 设计器在显示窗口方面正在做一些奇怪的幕后胡说八道,但这真的是发生了什么?这也可以解释为什么绑定到 Window 的 Title 或我的 CustomWindow 的 ContentText 属性在设计时也不起作用 - 设计时祖先可能不是真正的“窗口”。一定有办法解决这个问题,对吧?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...