【问题标题】:Fallback for missing style in themable application without applied theme没有应用主题的主题应用程序中缺少样式的后备
【发布时间】:2017-05-08 15:38:17
【问题描述】:

我有一个应用程序,它使用了几个可以在运行时切换的自定义主题。主题、应用程序和 UI(用户控件、对话框等)均位于单独的 .NET 程序集中。

主题不仅覆盖了控件的隐式默认样式(新控件模板),还提供了各种显式样式。

例子:

<!-- "Themes" assembly -->
<Style TargetType="Button" x:Key="DialogButtonStyle" 
       BasedOn="{StaticResource BaseButtonStyle}">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="Height" Value="24" />
    <Setter Property="MinWidth" Value="86" />
    <Setter Property="Padding" Value="8 0" />
</Style>

<!-- "UI" assembly -->
<Button Style="{DynamicResource DialogButtonStyle}"
        Content="OK" />

通过将所有样式、画笔等合并到应用程序资源中来应用主题,例如:

<Application x:Class="GUIDemo.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>    
        <ResourceDictionary x:Name="MainDictionary">
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary x:Name="ThemeDictionary">
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="/Themes;component/SystemTheme.xaml" />
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>    
    </Application.Resources>
</Application>

(或运行时对应的代码。)

问题:

是否可以在我的 UI 程序集(而不是应用程序程序集)中定义后备样式?如果应用程序未包含任何主题,则应自动应用这些主题,即当“DialogBu​​ttonStyle”等键未定义并导致输出中出现错误消息时。

我想要实现的是我的 UI 库是完全可主题化的,但也可以在无需关心自定义主题的情况下使用。

我尝试了什么:

(1) 定义一个包含后备样式的 dummy App.xaml。这在设计时(设计器预览、代码完成)有效,但在运行时无效。

(2) 在“Themes/Generic.xaml”中定义样式。这似乎只适用于隐式样式,不适用于显式样式。

(3) 将 Generic.xaml 合并到所有使用该样式的 XAML 文件的资源中。这不起作用,因为样式现在会覆盖主题。

【问题讨论】:

    标签: .net wpf themes wpf-style


    【解决方案1】:

    在您合并主题资源之前,尝试将后备样式合并到您的 ResourceDictionary 中:

    <Application.Resources>
        <ResourceDictionary x:Name="MainDictionary">
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="FallbackResources.xaml" />
                <ResourceDictionary Source="/Themes;component/SystemTheme.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
    

    然后主题资源 - 如果有的话 - 应该覆盖备用资源。

    不,我不是这个意思。我希望在 UI 程序集中(而不是应用程序)中定义回退。回退的全部意义在于确保即使应用程序确实正确应用了主题(或其他资源文件),样式也已定义。

    除非您将它们合并到您的应用程序中,否则应用程序无法应用这些备用资源。如果应用程序无法从外部程序集中应用任何资源字典,如果您尝试在视图中引用这些资源中的任何一个,您将获得运行时异常。资源必须以某种方式显式合并到应用程序中。

    【讨论】:

    • 不,我不是这个意思。我希望在 UI 程序集中(而不是应用程序)中定义回退。回退的重点是确保样式已定义,即使应用程序确实正确应用了主题(或其他资源文件)。
    • 那么不行。您需要明确告诉应用程序这些资源确实存在以及在哪里可以找到它们。我编辑了我的答案。
    • @mm8 这似乎不对,有几个标准 WPF 控件(例如 TextBox)具有默认颜色。在我的情况下,我正在构建一个使用网格的控件,该控件似乎具有透明的默认颜色,在这种情况下是不需要的。我认为它与模板有关,必须有一个默认模板或其他东西。
    【解决方案2】:

    我也在构建一个支持主题的控件库并遇到了这个问题。 您希望某人能够在未定义任何主题(并且看起来不奇怪)但同时支持主题颜色的项目中使用该控件。

    当没有向应用的资源添加主题时,找不到主题颜色(资源键)并且控件恢复为默认值。例如,TextBox 的白色背景上的黑色文本。在网格的情况下,它是透明的,这对于基于网格的弹出控件来说是一个问题。

    解决方案是隐式样式。

    基本上,您在需要它的级别(例如在网格中或在控件级别)定义一种样式,该样式针对特定类型并且不使用 x:key。

    相关问题:
    Implicit styles in Application.Resources vs Window.Resources?

    【讨论】:

      猜你喜欢
      • 2015-12-02
      • 1970-01-01
      • 1970-01-01
      • 2010-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      相关资源
      最近更新 更多