找不到样式的键入键

Type key for style not found

我创建了一个名为 FlatButton 的自定义用户控件,派生自 Button:

XAML:

<Button
    x:Class="Program.GUI.Controls.FlatButton"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:GUIControls="clr-namespace:Program.GUI.Controls"
    mc:Ignorable="d">
    <Button.Resources>
        <ResourceDictionary>
            <Style x:Key="{x:Type GUIControls:FlatButton}" TargetType="{x:Type GUIControls:FlatButton}" BasedOn="{StaticResource ResourceKey={x:Type Button}}">
                <Setter Property="OverridesDefaultStyle" Value="True"/>
                <Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
                <Setter Property="BorderThickness" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type GUIControls:FlatButton}">
                            <Grid x:Name="LayoutRoot" Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}">
                                <TextBlock
                                    x:Name="Text"
                                    Text="{TemplateBinding Content}"
                                    Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}"
                                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="LayoutRoot" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HoverBackground}"/>
                                    <Setter TargetName="Text" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HoverForeground}"/>
                                </Trigger>
                                <Trigger Property="IsMouseCaptured" Value="True">
                                    <Setter TargetName="LayoutRoot" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ClickBackground}"/>
                                    <Setter TargetName="Text" Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ClickForeground}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </Button.Resources>
</Button>

CS:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Program.GUI.Controls {
    /// <summary>
    /// Interaction logic for FlatButton.xaml
    /// </summary>
    public partial class FlatButton : Button {
        public static readonly DependencyProperty HoverBackgroundProperty = DependencyProperty.Register(
            "HoverBackground",
            typeof(Brush),
            typeof(FlatButton)
        );

        public static readonly DependencyProperty HoverForegroundProperty = DependencyProperty.Register(
            "HoverForeground",
            typeof(Brush),
            typeof(FlatButton)
        );

        public static readonly DependencyProperty ClickBackgroundProperty = DependencyProperty.Register(
            "ClickBackground",
            typeof(Brush),
            typeof(FlatButton)
        );

        public static readonly DependencyProperty ClickForegroundProperty = DependencyProperty.Register(
            "ClickForeground",
            typeof(Brush),
            typeof(FlatButton)
        );

        public Brush HoverBackground { get; set; }
        public Brush HoverForeground { get; set; }

        public Brush ClickBackground { get; set; }
        public Brush ClickForeground { get; set; }

        static FlatButton() {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(FlatButton), new FrameworkPropertyMetadata(typeof(FlatButton)));
        }

        public FlatButton() {
            this.InitializeComponent();
        }
    }
}

问题是当我尝试创建扩展样式时找不到基本样式:

主窗口XAML:

<Style x:Key="DefaultDarkButtonThemeStyle" TargetType="{x:Type GUIControls:FlatButton}" BasedOn="{StaticResource {x:Type GUIControls:FlatButton}}">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{DynamicResource ColorTextPrimaryDark}"/>
    <Setter Property="HoverBackground" Value="{DynamicResource ColorPrimaryDarkLight}"/>
    <Setter Property="HoverForeground" Value="{DynamicResource ColorTextPrimaryDarkLight}"/>
    <Setter Property="ClickBackground" Value="{DynamicResource ColorPrimaryDarkLightLight}"/>
    <Setter Property="ClickForeground" Value="{DynamicResource ColorTextPrimaryDarkLightLight}"/>
</Style>

异常:

System.Windows.Markup.XamlParseException: ''Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.' Line number '45' and line position '47'.'

Inner Exception
Exception: Cannot find resource named 'Program.GUI.Controls.FlatButton'. Resource names are case sensitive.

如果您开发一个像 FlatButton 这样的自定义控件,您应该创建一个单独的样式,如果您开发一个自定义控件库或任何其他专用资源字典。无论您选择哪种路径,您都可以将相应的资源字典合并到应用程序资源或较低范围内的任何其他资源字典中,以使该样式在该范围内可访问(如果它是 implicit 则自动应用它 或基于它创建样式,无论如何)。

您的部分 XAML 定义是创建 UserControl 的常用方法,但不适用于自定义控件。 Button 标记资源中 FlatButton 的样式只能在此本地资源字典 范围内解析 ,这意味着 FlatButton本身或向下它的视觉树。查看 static resource lookup behavior 以了解样式的解析方式和失败原因。

  1. The lookup process checks for the requested key within the resource dictionary defined by the element that sets the property.

  2. The lookup process then traverses the logical tree upward to the parent element and its resource dictionary. This process continues until the root element is reached.

  3. App resources are checked. App resources are those resources within the resource dictionary that is defined by the Application object for your WPF app.

因此,当您的 DefaultDarkButtonThemeStyle 在主 window 中创建 并尝试解析 GUIControls:FlatButton 基本样式时,它不会找到它,因为它没有在 window 资源中定义,也没有在可视化树或应用程序资源中的任何位置定义。

但是,如果您只是简单地创建了一个包含该样式的主题或常规资源字典并将其包含在 window 或应用程序资源中,它将成功解析。

有关创建自定义控件的更多信息,包括如何设置样式和资源字典,您可以参考Control authoring overview