WPF如何将样式应用到自定义控件项而不覆盖派生样式

Dae*_*ire 4 wpf xaml wpf-controls material-design material-design-in-xaml

我正在基于通用 Windows 搜索栏 (我的版本)在 wpf 中构建自定义控件搜索框。在 Windows 实现中,按钮将根据是否按下按钮来改变背景和前景。为此,我使用样式和触发器来更改按钮颜色。

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

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

Generic.xaml-自定义按钮

 <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>
Run Code Online (Sandbox Code Playgroud)

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

 <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
Run Code Online (Sandbox Code Playgroud)

我尝试过的

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

从基于“Material Design 主题丢失”常见问题解答的 Material 样式派生 ,会导致以下错误:异常:找不到名为“MaterialDesignFlatButton”的资源。资源名称区分大小写。

Generic.Xaml 尝试更改 CustomButton

<!--Same custon control as before--->
<Button.Style>
    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatButton}">
        <!--same trigger-->
Run Code Online (Sandbox Code Playgroud)

Bio*_*ode 8

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

您的其余方法是正确的。

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

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

<Style TargetType="local:CustomButton" 
       BasedOn="{StaticResource MaterialDesignFlatButton}" />
Run Code Online (Sandbox Code Playgroud)

更新

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

您不仅扩展了Button,还覆盖了Style扩展的默认值Button。执行此操作需要在Generic.xamlStyle文件中定义默认值。由于解析此默认资源的方式,此文件不允许合并字典。仅允许引用相同Generic.xaml中的资源。ResourceDictionary

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

  <Style TargetType="CustomButton" 
         BasedOn="{StaticResource MaterialDesignFlatButton}">
    <Setter Property="OverridesDefaultStyle" Value="True" />
  </Style>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)

评论

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

DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomButton), 
  new FrameworkPropertyMetadata(typeof(CustomButton)));
Run Code Online (Sandbox Code Playgroud)

将现已过时的默认值合并到 override 后StyleCustomButtonStyle的覆盖Style可能如下所示:

应用程序.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>
Run Code Online (Sandbox Code Playgroud)