【问题标题】:WPF how to apply a style to a custom control item without overriding the derived styleWPF 如何在不覆盖派生样式的情况下将样式应用于自定义控件项
【发布时间】:2020-06-09 16:30:30
【问题描述】:

我正在 wpf 中基于 common windows search bar (my version) 构建一个自定义控件搜索框。在 Windows 实现中,按钮将根据是否按下它们来改变背景和前景。为此,我使用样式和触发器来更改按钮颜色。

当我使用 MaterialDesign 时,我的自定义控件包含一个使用派生/默认 material design button 的按钮。将样式应用于此按钮时,材料设计样式为overridden,支持默认的 wpf 按钮。如何在保持基础材料设计风格的同时应用风格?

由于我的问题仅在于将样式应用于按钮,因此我省略了搜索框样式,而是创建了一个仅包含按钮的问题示例。

Generic.xaml -CustomButton

 <Style TargetType="{x:Type local:CustomButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomButton}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <!-- Normally the below button would be inside a grid with additional buttons, labels and content presenter. I have removed these for simplicity-->
                        <Button Name="MaterialButton"
                                Content="CustomButton">
                            <Button.Style>
                                <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type  Button}}">
                                    <Style.Triggers>
                                        <Trigger Property="IsMouseOver" Value="True">
                                            <Setter Property="Foreground" Value="Red"/>
                                        </Trigger>
                                    </Style.Triggers>
                                </Style>
                            </Button.Style>
                        </Button>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

App.xaml -(材料设计在资源字典中。)

 <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

我的尝试

我已尝试按照建议的herehere 使用BasedOn 属性,但这并没有解决我的问题。

源自基于"Material Design theme is lost" 的材质样式 常见问题解答,导致此错误: 例外:找不到名为“MaterialDesignFlatButton”的资源。资源名称区分大小写。

Generic.Xaml 尝试更改 CustomButton

<!--Same custon control as before--->
<Button.Style>
    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatButton}">
        <!--same trigger-->

【问题讨论】:

    标签: wpf xaml material-design wpf-controls material-design-in-xaml


    【解决方案1】:

    您似乎没有安装正确的依赖项。右键单击使用该样式的项目并选择 NuGet 包管理器。搜索 MaterialDesignThemes 包并安装它。如果已经安装,请重新安装。这应该可以解决它。

    你的其余方法是正确的。

    或者从 GitHub 存储库复制 original style(快照)和所有引用并将其粘贴到您的 App.xaml

    如果安装了所有依赖项(或复制了原始样式),则使用以下Style 将MaterialDesign 默认Button 样式应用于您的CustomButton

    <Style TargetType="local:CustomButton" 
           BasedOn="{StaticResource MaterialDesignFlatButton}" />
    

    更新

    现在您已经编辑了您的问题以提供必要的详细信息,我可以告诉您出了什么问题。

    您不仅扩展了Button,还覆盖了扩展Button 的默认Style。这样做需要在 Generic.xaml 文件中定义默认的 Style。由于此默认资源的解析方式,此文件不允许合并字典。只允许引用 Generic.xaml 的同一 ResourceDictionary 中的资源。

    要解决这个问题,您需要显式覆盖默认的Style。覆盖Style 必须在MaterialDesignFlatButton 资源的范围内,否则引用将无法解析并导致您之前发布的错误消息。以下示例在 App.xaml 中定义了覆盖 Style

      <Style TargetType="CustomButton" 
             BasedOn="{StaticResource MaterialDesignFlatButton}">
        <Setter Property="OverridesDefaultStyle" Value="True" />
      </Style>
    </ResourceDictionary>
    

    备注

    由于您显然对默认 Style 不感兴趣,因此您应该合并此默认 Style 的详细信息,例如ControlTemplate 进入覆盖 Style。然后,您可以从 Generic.xaml 中删除默认的 Style。然后,您还需要从自定义控件的 static 构造函数中删除以下行,例如CustomButton

    DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomButton), 
      new FrameworkPropertyMetadata(typeof(CustomButton)));
    

    将现在已过时的默认 StyleCustomButton 合并到覆盖 Style 后,新的覆盖 Style 可能如下所示:

    App.xaml

    <Style TargetType="local:CustomButton"
           BasedOn="{StaticResource MaterialDesignFlatButton}">
      <Setter Property="OverridesDefaultStyle" Value="True" />
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type local:CustomButton}">
            <Border Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">
              <ContentPresenter />
            </Border>
    
            <ControlTemplate.Triggers>
              <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Foreground" Value="Red" />
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    

    【讨论】:

    • 感谢使用原始样式的建议,如果找不到简单的解决方案,我会使用它。 MaterialDesignThemes 似乎安装正确,works as expected 未应用样式时。将样式应用于自定义控件中的项目时会出现问题 - 该项目默认为 wpf 主题。我可以覆盖自定义控件之外的项目,并且样式和材料设计主题都按预期应用。
    • 我不明白。您发布了一条错误消息,其中显示样式 MaterialDesignFlatButton 无法解析。这就是为什么我写你应该查找并安装 MaterialDesignThemes 包。因此,除了您的CustomButton 之外,所有样式都隐式应用于应用程序范围内?确保您使用的是正确的Style。它必须是&lt;Style TargetType="local:CustomButton" BasedOn="{StaticResource MaterialDesignFlatButton}" /&gt;。试试这种风格。我会更新我的答案。
    • 抱歉造成混淆,显式覆盖是我尝试解决问题的一个示例。我已经编辑了我的答案以帮助澄清这一点。 Material Design 样式是应用程序范围内的,包括我的自定义控件中的项目。当我将样式应用于自定义控件(在本例中为“MaterialButton”)中的项目时,它会丢失其材料设计主题,而不是默认的 wpf。我试图在应用样式的同时保留材料设计主题。这可以在页面或窗口等中的自定义控件之外完成。此问题仅出现在自定义控件中。
    • 您的最新更新为黑暗带来了一丝曙光。我不知道您正在尝试将这个资源合并到 Generic.xaml 中。我怎么会知道这个。既然你提到了这一点,我立刻明白了你的问题。我已经更新了我的答案以应对这种新情况。 Generic.xaml 不允许合并字典作为参考。所有引用的资源都必须在 Generic.xamlResourceDictionary 内定义。我一直期待您在 App.xaml 中定义 Style。请尝试我的回答,如果这解决了您的问题,请告诉我。
    • 我也意识到你的ControltemplateCustomButton 是相当无意义的。没有必要在按钮内放置按钮。所以我删除了这个多余的内部Button。您通常会在模板中添加一个简单的ContentPresenter。这个ContentPresenter 将自动绑定到ContentControl.Content 属性以呈现内容值。请检查并尝试我的最新更新。
    猜你喜欢
    • 2010-12-02
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 2019-10-31
    • 2019-07-20
    • 1970-01-01
    相关资源
    最近更新 更多