WPF、自定义控件和 style/theme 继承
WPF, custom controls, and style/theme inheritance
我正在处理一个已经存在的项目,我无法按照我想要的方式设置样式。
我从一个应用程序开始:
- 在 Resources 文件夹中有一个 WhistlerBlue.xaml 文件。
- 文件中的样式使用 TargetType 自动应用它们
- 有一个为 Expander 控件定义的样式(更多内容,下一个)
- 我不想弄乱这个文件。
- 该文件通过 App.xaml
中的合并资源在应用程序中明确使用
到目前为止,一切正常。
然后...
我正在构建一个派生自 Expander:
的自定义控件
internal partial class TestExpander : Expander
通过创建自定义控件,VStudio 已将 Theme 文件夹添加到项目中,其中包含通常的 Generic.xaml里面的文件。在这个文件中,我为自定义控件创建了样式:
<Style TargetType="{x:Type local:TestExpander}" BasedOn="{StaticResource {x:Type Expander}}">
<Style.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility"/>
</Style.Resources>
<Setter Property="ExpandDirection" Value="Down"/>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Cursor" Value="Hand"/>
</Style>
显然在自定义控件的代码中我有:
static TestExpander()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TestExpander), new FrameworkPropertyMetadata(typeof(TestExpander)));
}
我期望我的 TestExpander 继承 WhistlerBlue.xaml[ 中定义的 Expander 样式=51=], 加上自己的个性风格, 从此过上了幸福的生活。
这没有发生。我哪里错了?
因此,当我们为各种事物创建继承架构时,很容易忘记事物接收其继承部分的顺序。因此,例如,当我们放置一个直接查看 x:Type
的 BasedOn 时,它就会按照它可用的继承顺序去寻找它,对吗?
当它正在寻找 x:Type
并且它不知道另一个字典中的覆盖时......他直接进入默认的原始字典。但是,如果我们注入包含您想要通过 ResourceDictionary.MergedDictionaries
继承的内容的字典,那么它知道在他返回框架默认值之前先看看他,世界上一切都很好。
附带说明一下,当您以这种方式合并字典以进行继承时,您必须注意自己的操作方式,否则可能会影响性能。因为说它是一个合并的字典....在运行时它会合并字典中的所有内容并将所有内容复制到新字典中。
所以对于这个例子......如果是我,我可能会忽略 generic.xaml 词典内容,如果它不是真的必要的话,并将该模板放在现有词典中,就在模板所在的位置下面寻找继承自放置。那么你就不会再复制一整本字典,它仍然会得到它的继承,生活应该是美好的。希望这可以帮助。 :)
我正在处理一个已经存在的项目,我无法按照我想要的方式设置样式。
我从一个应用程序开始:
- 在 Resources 文件夹中有一个 WhistlerBlue.xaml 文件。
- 文件中的样式使用 TargetType 自动应用它们
- 有一个为 Expander 控件定义的样式(更多内容,下一个)
- 我不想弄乱这个文件。
- 该文件通过 App.xaml 中的合并资源在应用程序中明确使用
到目前为止,一切正常。
然后...
我正在构建一个派生自 Expander:
的自定义控件internal partial class TestExpander : Expander
通过创建自定义控件,VStudio 已将 Theme 文件夹添加到项目中,其中包含通常的 Generic.xaml里面的文件。在这个文件中,我为自定义控件创建了样式:
<Style TargetType="{x:Type local:TestExpander}" BasedOn="{StaticResource {x:Type Expander}}">
<Style.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility"/>
</Style.Resources>
<Setter Property="ExpandDirection" Value="Down"/>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Cursor" Value="Hand"/>
</Style>
显然在自定义控件的代码中我有:
static TestExpander()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TestExpander), new FrameworkPropertyMetadata(typeof(TestExpander)));
}
我期望我的 TestExpander 继承 WhistlerBlue.xaml[ 中定义的 Expander 样式=51=], 加上自己的个性风格, 从此过上了幸福的生活。
这没有发生。我哪里错了?
因此,当我们为各种事物创建继承架构时,很容易忘记事物接收其继承部分的顺序。因此,例如,当我们放置一个直接查看 x:Type
的 BasedOn 时,它就会按照它可用的继承顺序去寻找它,对吗?
当它正在寻找 x:Type
并且它不知道另一个字典中的覆盖时......他直接进入默认的原始字典。但是,如果我们注入包含您想要通过 ResourceDictionary.MergedDictionaries
继承的内容的字典,那么它知道在他返回框架默认值之前先看看他,世界上一切都很好。
附带说明一下,当您以这种方式合并字典以进行继承时,您必须注意自己的操作方式,否则可能会影响性能。因为说它是一个合并的字典....在运行时它会合并字典中的所有内容并将所有内容复制到新字典中。
所以对于这个例子......如果是我,我可能会忽略 generic.xaml 词典内容,如果它不是真的必要的话,并将该模板放在现有词典中,就在模板所在的位置下面寻找继承自放置。那么你就不会再复制一整本字典,它仍然会得到它的继承,生活应该是美好的。希望这可以帮助。 :)