如何基于 MaterialDesign 构建自定义组件?

Posted

技术标签:

【中文标题】如何基于 MaterialDesign 构建自定义组件?【英文标题】:How to build a custom component based on MaterialDesign? 【发布时间】:2021-05-31 18:27:11 【问题描述】:

我正在尝试了解如何基于材料设计构建自定义组件,以了解实现该过程的确切过程是如何工作的,我想构建一个包含文本和图标的简单按钮(记住只是用于锻炼),所以我尝试同时编写UserControlResurceDictionary,但到目前为止还没有运气。我的问题是,如何根据材料设计构建自定义按钮?我希望它保持 Material Design 附带的所有效果和阴影。我还将发布我所拥有的ResurceDictionary

资源字典

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:local="clr-namespace:KESS3Mockup">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
    </ResourceDictionary.MergedDictionaries>

    <Style TargetType="x:Type local:VerticalButton" BasedOn="StaticResource ResourceKey=x:Type Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type local:VerticalButton">
                    <Border Background="TemplateBinding Background"
                            BorderBrush="TemplateBinding BorderBrush"
                            CornerRadius="2"
                            BorderThickness="TemplateBinding BorderThickness">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="0.5*"/>
                                    <RowDefinition Height="8*"/>
                                    <RowDefinition Height="8*"/>
                                    <RowDefinition Height="0.5*"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="1*"/>
                                    <ColumnDefinition Width="20*"/>
                                    <ColumnDefinition Width="1*"/>
                                </Grid.ColumnDefinitions>
                                <Viewbox HorizontalAlignment="Stretch"  Grid.Column="1" Grid.Row="1">
                                    <materialDesign:PackIcon Kind="TemplateBinding Kind" Foreground="White" />
                                </Viewbox>
                                <Viewbox Grid.Column="1" Grid.Row="2">
                                    <TextBox Text="TemplateBinding Text" Foreground="White" SelectionBrush="#000078D7" BorderBrush="#00000000" Focusable="False"/>
                                </Viewbox>
                            </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

【问题讨论】:

将自定义控件的样式基于 Material Design 样式?或者你的问题到底是什么? @mm8 是的,这就是我的目标 【参考方案1】:

您可以使用 BasedOn 在现有样式的基础上创建新样式。

<Style TargetType="x:Type local:VerticalButton" BasedOn="StaticResource x:Type Button">

除了类型,您还可以引用不同的特定样式。

<Style TargetType="x:Type local:VerticalButton" BasedOn="StaticResource MaterialDesignFlatButton"/>

但是,要使其工作,目标类型必须兼容(相同类型或基本类型,例如 ButtonBase 用于 Button)。您不能简单地创建UserControl 并基于Button 的样式创建样式。为了自定义Button,您必须创建一个继承自Button 的自定义控件VerticalButton,它实现了您想要的依赖属性和细节。

public class VerticalButton : Button

   static VerticalButton()
   
      DefaultStyleKeyProperty.OverrideMetadata(typeof(VerticalButton), new FrameworkPropertyMetadata(typeof(VerticalButton)));
   

   // ...your custom code.

接下来,您将在项目的Themes 文件夹中创建一个Generic.xaml 文件(此路径和文件按约定命名)。您可以在此处定义默认样式,该样式可以基于 Material Design。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:YourProject">

   <Style TargetType="x:Type local:VerticalButton" BasedOn="StaticResource x:Type Button">
      <!-- ...your style definitions. -->
   </Style>

</ResourceDictionary>

此资源词典必须包含在 App.xaml 中的 Material Design 主题词典之后。有关如何覆盖默认 Material Design 主题的更多信息,您可以refer to the Wiki。

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

请注意,尽管您可以将一种样式基于另一种样式,但您不能基于另一种控件模板。这意味着,如果您在样式中指定 ControlTemplate,它将覆盖基本样式之一。因此,如果您想调整控件模板,同时保留其大部分默认视觉效果和效果,您必须copy it from the Material Design GitHub repository 并根据您的需要进行调整。

有关开发自定义控件的更多信息,请参阅Control authoring overview。 Material Design 使用已建立的主题、样式和模板概念,因此它与标准 WPF 控件的样式或构建自定义控件没有真正的区别。

对于自定义按钮内容的简单案例,创建一个DataTemplate 并指定为ButtonContentTemplate 可能是一种更简单的替代方法,请参阅Data Templating Overview。

【讨论】:

【参考方案2】:

当您设置控件模板时,它会覆盖所有视觉样式。它仅带有依赖属性。因此,它不会带有任何阴影或其他效果(至少对您的新风格而言)。但是,如果此类属性存在于 VerticalButton 类(您的目标)中,那么您可以重用此类属性并定义您自己的样式。

【讨论】:

以上是关于如何基于 MaterialDesign 构建自定义组件?的主要内容,如果未能解决你的问题,请参考以下文章

如何自定义构建基于 Jquery 的 javascript API 以及关于 Jquery 中使用的语法的一些问题

Material Design系列,自定义Behavior支持所有View

如何全局构建自定义比较器函数?

Material Design系列,自定义Behavior之上滑显示返回顶部按钮

Material Design系列,自定义Behavior实现Android知乎首页

Material design 2 自定义css组件