wpf集成MaterialDesignThemes
介绍
MaterialDesignThemes 是一个基于 WPF(Windows Presentation Foundation) 的开源 UI 框架,用于实现现代化的 Material Design 风格界面。它提供了丰富的控件、样式、主题和动画,帮助开发者快速构建美观、一致的桌面应用程序。
官网:https://materialdesigninxaml.net/
核心功能与特性
- 预定义控件库
包含 Material Design 规范中的常用控件,例如:
- 按钮(Button、FlatButton、RaisedButton)
- 输入框(TextBox、PasswordBox、TextBoxHelper)
- 导航控件(NavigationView、TabControl)
- 布局控件(Card、Grid、StackPanel)
- 通知控件(Snackbar、Dialog)
- 数据控件(DataGrid、ListView)
- 图标支持(集成 Material Design Icons 字体库,可通过 PackIcon 控件调用)。
- 主题与样式系统
- 内置主题:支持浅色(Light)、深色(Dark)和高对比度(High Contrast)主题,可通过修改资源字典快速切换。
<!-- 浅色主题 -->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Light.xaml" />
<!-- 深色主题 -->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Dark.xaml" />
- 自定义主题:可通过修改颜色值(如主色 PrimaryColor、强调色 AccentColor)来自定义主题风格。
- 动画与过渡效果
提供多种 Material Design 风格的动画,例如:
- 按钮点击涟漪效果(Ripple Effect)
- 控件淡入淡出、展开收缩过渡(如 TransitioningContent 控件的 OpeningEffect 和 ClosingEffect)。注意****:在较新版本中,部分过渡效果可能调整了名称或参数,建议参考 官方文档 确认用法。
- 行为与附加属性
- 内置 MaterialDesignXamlBehaviors 库,支持手势操作、数据绑定增强等功能。
- 附加属性简化控件配置,例如:
<Button md:ButtonAssist.Pressable="True" /> <!-- 启用按钮按压反馈 -->
<TextBox md:TextBoxHelper.PasswordChar="•" /> <!-- 密码框掩码字符 -->
下载资源包

全局配置应用资源
打开App.xaml文件,添加Material Design的资源字典,通过全局资源字典将Material Design风格应用到整个应用程序。
- 先在头部引入Material Design的命名空间
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
- 在Application.Resources中配置资源字典
<Application.Resources>
<!-- Material Design 基础资源 -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<!-- 必需的 Material Design 资源 -->
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
注意:在老版本Material Design中ResourceDictionary的Source用下面这个也是可以的。但是新版本不能用,否则会报错:找不到资源“themes/materialdesigntheme.defaults.xaml****”。
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
- BaseTheme:基础主题(Dark 或 Light),控制整体明暗风格(背景、字体颜色等)。
- PrimaryColor:主色(如界面主色调、按钮默认颜色)。
- SecondaryColor:辅助色(如按钮悬停 / 选中颜色、强调色)。
局部配置应用资源
如果不想全局应用Material Design库,想要混合使用原生控件和Material Design控件,可以在需要的窗口中配置Material Design资源字典。只需要把对应的配置放在Window.Resources标签里即可。
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
常用主题资源路径
- 基础默认值(必须引用)
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
- 应用的主题样式:浅色主题还是深色主题
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Dark.xaml" />
原生控件自动应用Material Design样式
由于MaterialDesign3.Defaults.xaml已被加载,所有原生的WPF控件都会自动应用Material Design样式。
<Grid>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Content="Button" Width="100" Height="30"/>
</StackPanel>
</Grid>

附加属性
- 浮动标签:类似于提示文本,未输入时:提示文本显示在输入框内部,作为占位符。输入内容时:提示文本平滑上浮到输入框顶部,并缩小字体,成为一个标签。输入框有内容但失去焦点时:提示文本保持在顶部。
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
<TextBox Margin="20,0" Width="200" md:HintAssist.Hint="请输入账号"/>
未输入时:

输入内容时:

常用的HintAssist属性
| 属性名 | 作用 |
|---|---|
| HintAssist.Hint | 设置提示文本内容。 |
| HintAssist.Foreground | 设置提示文本的颜色(默认使用主题色)。 |
| HintAssist.IsFloating | 控制是否启用浮动效果(默认为True)。 |
| HintAssist.HintOpacity | 设置提示文本的透明度(输入时会自动调整)。 |
| HintAssist.UseFloatingHintWhenNotEmpty | 当输入框有内容但失去焦点时,是否保持浮动标签效果(默认为 True)。 |
- 清除按钮:md:TextFieldAssist.HasClearButton="True" 是 MaterialDesignInXamlToolkit 中用于为文本框(TextBox 或 TextField)添加清除按钮(X 按钮)的附加属性。当用户输入内容时,清除按钮会自动显示,点击可快速清空文本框内容。
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
<TextBox Width="250" VerticalAlignment="Center" md:TextFieldAssist.HasClearButton="True" md:HintAssist.Hint="请输入账号"/>
输入内容后,右侧会出现清除图标,点击可清除TextBox内容。

- 常用TextFieldAssist属性
| 附加属性 | 说明 |
|---|---|
| md:TextFieldAssist.HasClearButton | 是否显示清除按钮(布尔值,默认False) |
| md:TextFieldAssist.ClearButtonVisibility | 控制清除按钮的显示时机, 可选值: Visible(始终显示) WhenFocused(获得焦点时显示) WhenFocusedOrNotEmpty(焦点或非空时显示,默认) |
| md:TextFieldAssist.ClearButtonCommand | 自定义清除按钮的命令(默认使用内部清空命令) |
| md:TextFieldAssist.ClearButtonContent | 自定义清除按钮的内容(如改用图标 |
消息通知Snackbar
- 作用:在界面底部显示轻量级的临时消息通知,具体如下:
- 临时通知:在不干扰用户主操作的前提下,显示简短的消息(如操作结果、系统提示)。
- 交互选项:可包含一个可选的操作按钮(如 “撤销”)。
- 自动消失:默认几秒后自动消失,无需用户手动关闭。
- 核心属性:MessageQueue
- 类型:IMessageQueue
- 作用:Snackbar 的消息队列,用于管理和显示消息。
- {md:MessageQueue} 是一个 标记扩展,自动创建并绑定一个全局单例消息队列。
- 示例代码:
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
<Grid>
<md:Snackbar x:Name="MySnackBar" MessageQueue="{md:MessageQueue}" />
</Grid>
MySnackBar.MessageQueue.Enqueue("HelloWorld");

- 常用配置选项:
| 属性 | 作用 |
|---|---|
| MessageQueue | 绑定消息队列。 |
| VerticalAlignment | 位置(通常为Bottom)。 |
| IsActive | 控制 Snackbar 是否显示(可绑定布尔值)。 |
| Duration | 消息显示时间(默认TimeSpan.FromSeconds(2.75))。 |
| ActionContent | 操作按钮文本(如 “撤销”)。 |
| ActionCommand | 操作按钮的命令。 |
页面切换动画Transitioner
- md:Transitioner 是 Material Design In XAML Toolkit 提供的一个容器控件,用于实现 页面切换动画。它类似于原生 WPF 的 TabControl,但专注于提供流畅的过渡效果。
- 主要功能如下:
- 多页面容器:可以包含多个 md:TransitionerSlide 子元素,每个 Slide 代表一个 "页面"。
- 切换动画:在页面切换时自动应用动画效果(如淡入淡出、滑动等)。
- 索引控制:通过 SelectedIndex 属性指定当前显示的页面。
- 常用属性:
| 属性名 | 作用 |
|---|---|
| SelectedIndex | 当前选中的页面索引(从 0 开始)。可绑定到 ViewModel 中的属性。 |
| Transition | 指定切换动画类型(默认MaterialDesignTransitionEffect)。 |
| ItemsSource | 绑定数据源,用于动态生成页面(类似ItemsControl)。 |
| ItemTemplate | 定义数据项的显示模板。 |
- 示例代码
通过点击按钮,切换不同的页面。
View
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:vm="clr-namespace:WpfApp2.ViewModels"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 导航按钮 -->
<StackPanel Orientation="Horizontal" Margin="10" Grid.Row="0">
<Button Content="页面1"
Command="{Binding}"
CommandParameter="0"
Style="{StaticResource MaterialDesignRaisedButton}"
Margin="5"/>
<Button Content="页面2"
Command="{Binding}"
CommandParameter="1"
Style="{StaticResource MaterialDesignRaisedButton}"
Margin="5"/>
</StackPanel>
<md:Transitioner SelectedIndex="{Binding SelectIndex,FallbackValue=0}" Grid.Row="1">
<md:TransitionerSlide>
<Grid Background="LightBlue">
<TextBlock Text="页面一" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</md:TransitionerSlide>
<md:TransitionerSlide>
<Grid Background="LightGreen">
<TextBlock Text="页面二" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
</md:TransitionerSlide>
</md:Transitioner>
</Grid>
</Window>
ViewModel
public class MainViewModel : INotifyPropertyChanged, ICommand
{
private int _selectIndex;
public int SelectIndex
{
get => _selectIndex;
set => SetProperty(ref _selectIndex, value);
}
// 实现 ICommand 接口
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => true;
public void Execute(object parameter)
{
if (parameter is string indexStr && int.TryParse(indexStr, out int pageIndex))
{
SelectIndex = pageIndex;
}
}
// 实现 INotifyPropertyChanged 接口
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return;
field = value;
OnPropertyChanged(propertyName);
}
protected virtual void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
效果:默认显示页面一,点击页面2按钮切换到页面二,再次点击页面一按钮切换到页面一。默认动画效果为淡入淡出。


全局弹窗&抽屉DialogHost
- 介绍:md:DialogHost 是 MaterialDesignInXamlToolkit 库中最重要的控件之一,用于在 WPF 应用中实现 全局弹窗(Dialog) 和 抽屉(Drawer) 功能。它提供了统一的模态 / 非模态对话框管理、动画效果和键盘导航,是 Material Design 交互规范的核心组件。
- md:DrawerHost 实现侧边抽屉菜单(左 / 右侧),支持动画滑入滑出。
- 关键属性:
- IsLeftDrawerOpen/IsRightDrawerOpen:控制抽屉的打开状态(绑定布尔值)。
- LeftDrawerContent/RightDrawerContent:定义抽屉内容(通常为 StackPanel 或 ListBox)。
- DrawerWidth:设置抽屉宽度(默认 240)。
- DrawerBackground:设置抽屉背景色。
- 主要功能
- 全局弹窗管理
- 显示模态或非模态对话框,覆盖整个应用界面。
- 自动处理弹窗的层级关系,确保弹窗显示在所有内容之上。
- 抽屉导航
- 支持左侧或右侧抽屉菜单,通过动画滑入滑出。
- 与 DrawerHost 结合使用,实现响应式布局。
- 交互规范
- 内置键盘导航(如 Esc 键关闭弹窗 / 抽屉)。
- 支持触摸操作和鼠标交互。
- 示例代码
View
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:vm ="clr-namespace:WpfApp2.ViewModels"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:MainViewModel/>
<!-- 绑定 ViewModel -->
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<!-- 左侧按钮区固定宽度 -->
<ColumnDefinition Width="*"/>
<!-- 右侧内容区 -->
</Grid.ColumnDefinitions>
<!-- 左侧区域:按钮栏 -->
<StackPanel Grid.Column="0" Background="#F5F5F5" Margin="20">
<!-- 设置按钮宽高,确保可点击 -->
<Button
Content="打开抽屉"
Command="{Binding OpenDrawerCommand}"
Width="120" Height="40"
Margin="10"/>
<Button
Content="关闭抽屉"
Command="{Binding CloseDrawerCommand}"
Width="120" Height="40"
Margin="10"/>
</StackPanel>
<!-- 右侧区域:抽屉宿主 -->
<md:DrawerHost Grid.Column="1" IsRightDrawerOpen="{Binding IsDrawerOpen}">
<!-- 右侧抽屉内容 -->
<md:DrawerHost.RightDrawerContent>
<DockPanel Width="300" LastChildFill="False">
<TextBlock Padding="20,10" DockPanel.Dock="Top" FontSize="20" FontWeight="Bold" Text="{Binding LoginTitle}" />
<TextBox Margin="20,0" md:HintAssist.Hint="请输入账号" DockPanel.Dock="Top" Text="{Binding Account}" />
<TextBox MinHeight="100" Margin="20" md:HintAssist.Hint="请输入密码" DockPanel.Dock="Top" Text="{Binding Password}" />
<Button Margin="20,0" Command="{Binding ExecuteCommand}" CommandParameter="SaveData" Content="保存" DockPanel.Dock="Top" />
</DockPanel>
</md:DrawerHost.RightDrawerContent>
</md:DrawerHost>
</Grid>
</Window>
ViewModel
public class MainViewModel : INotifyPropertyChanged
{
// 实现INotifyPropertyChanged接口
public event PropertyChangedEventHandler? PropertyChanged;
// 通知属性变更的方法
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// 抽屉状态属性
private bool _isDrawerOpen;
public bool IsDrawerOpen
{
get => _isDrawerOpen;
set
{
if (_isDrawerOpen != value)
{
_isDrawerOpen = value;
OnPropertyChanged();
}
}
}
// 登录标题属性
private string _loginTitle = "用户登录";
public string LoginTitle
{
get => _loginTitle;
set
{
if (_loginTitle != value)
{
_loginTitle = value;
OnPropertyChanged();
}
}
}
// 账号属性
private string _account = "";
public string Account
{
get => _account;
set
{
if (_account != value)
{
_account = value;
OnPropertyChanged();
}
}
}
// 密码属性
private string _password = "";
public string Password
{
get => _password;
set
{
if (_password != value)
{
_password = value;
OnPropertyChanged();
}
}
}
// 打开抽屉命令
private ICommand? _openDrawerCommand;
public ICommand OpenDrawerCommand
{
get
{
return _openDrawerCommand ??= new RelayCommand(
execute: _ => { IsDrawerOpen = true; },
canExecute: _ => true
);
}
}
// 关闭抽屉命令
private ICommand? _closeDrawerCommand;
public ICommand CloseDrawerCommand
{
get
{
return _closeDrawerCommand ??= new RelayCommand(
execute: _ => { IsDrawerOpen = false; },
canExecute: _ => true
);
}
}
// 执行命令
private ICommand? _executeCommand;
public ICommand ExecuteCommand
{
get
{
return _executeCommand ??= new RelayCommand(
execute: parameter => Execute(parameter as string),
canExecute: _ => true
);
}
}
// 命令执行方法
private void Execute(string? command)
{
switch (command)
{
case "SaveData":
SaveData();
break;
default:
Console.WriteLine($"未知命令: {command}");
break;
}
}
// 保存数据方法
private void SaveData()
{
Console.WriteLine($"保存数据 - 账号: {Account}, 密码: {Password}");
// 这里可以添加实际的数据保存逻辑
// 例如调用服务层保存到数据库
// 保存成功后关闭抽屉
IsDrawerOpen = false;
}
}
// 简单的RelayCommand实现
public class RelayCommand : ICommand
{
private readonly Action<object?> _execute;
private readonly Func<object?, bool>? _canExecute;
public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler? CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object? parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object? parameter)
{
_execute(parameter);
}
}


- 常用属性
| 属性名 | 类型 | 作用说明 |
|---|---|---|
| DialogContent | DataTemplate | 定义弹窗的内容模板 |
| DialogOpened | RoutedEventHandler | 弹窗打开时触发的事件 |
| DialogClosing | RoutedEventHandler | 弹窗关闭时触发的事件(可取消关闭) |
| DialogClosed | RoutedEventHandler | 弹窗关闭后的事件 |
| IsDrawerOpen | bool | 控制抽屉的打开状态(配合DrawerHost使用) |
| KeyTipTarget | UIElement | 设置键盘快捷键提示的目标元素 |
- 内置命令
| 命令名 | 作用说明 |
|---|---|
| OpenDialogCommand | 打开弹窗(参数为弹窗内容或数据上下文) |
| CloseDialogCommand | 关闭当前弹窗(可传递返回值) |
| ToggleDrawerCommand | 切换抽屉的打开 / 关闭状态 |
| OpenDrawerCommand | 打开抽屉 |
| CloseDrawerCommand | 关闭抽屉 |
创建弹出式菜单或浮动内容PopupBox
- 介绍:PopupBox 是一个容器控件,类似于原生 WPF 的 Popup,md:PopupBox 是 MaterialDesignInXamlToolkit 中的一个控件,用于创建弹出式菜单或浮动内容。
- 特点:
- 内置 Material Design 样式和动画。
- 支持相对定位(上、下、左、右)。
- 可自定义触发方式(点击、悬停等)。
- 自动处理焦点和关闭逻辑。
- 关键属性
定位属性
| 属性 | 说明 |
|---|---|
| HorizontalAlignment | 控制弹出框的水平对齐方式(Left/Center/Right/Stretch) |
| VerticalAlignment | 控制弹出框的垂直对齐方式 |
| Placement | 指定弹出方向(Bottom/Top/Left/Right/Mouse等) |
| PlacementTarget | 指定弹出框相对于哪个元素定位(默认为自身) |
显示控制
| 属性 | 说明 |
|---|---|
| IsOpen | 控制弹出框是否打开(可绑定到 ViewModel) |
| Trigger | 指定触发方式(Click/Hover/Focus/Explicit) |
| StaysOpen | 是否保持打开状态(默认为 false,点击外部关闭) |
层级与样式
| 属性 | 说明 |
|---|---|
| Panel.ZIndex | 设置控件的 Z 轴层级(值越大越靠前,可解决被遮挡问题) |
| PopupStyle | 自定义弹出框的样式 |
| Child | 弹出框内的内容 |
- 示例代码:
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
删除
<md:PopupBox HorizontalAlignment="Center" Cursor="">
<Button Content="删除" />
</md:PopupBox>


内容过渡动画TransitioningContent
- 介绍:TransitioningContent 是 MaterialDesignThemes 中用于实现 内容过渡动画 的容器控件。它可以包裹任意内容(如文本、按钮、面板等),并在内容显示 / 隐藏时自动应用指定的过渡效果,提升界面交互的流畅性和视觉体验。
- 核心属性
- Content:需要显示的内容(可绑定数据或直接设置)。
- OpeningEffect:内容显示时的入场动画效果。
- ClosingEffect:内容隐藏时的出场动画效果。(新版本不支持此属性)
- 示例代码
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
<md:TransitioningContent OpeningEffect="{md:TransitionEffect Kind=ExpandIn, Duration=0:0:0.5}">
<TextBlock Text="这是会展开显示的内容" FontSize="16"/>
</md:TransitioningContent>
或者
<md:TransitioningContent Content="这是会展开显示的内容" FontSize="16" OpeningEffect="{md:TransitionEffect Kind=ExpandIn, Duration=0:0:0.5}">
</md:TransitioningContent>
TransitionEffect
Kind属性
| 效果类型 | 说明 |
|---|---|
| None | 无动画(直接显示) |
| ExpandIn | 展开(宽度/高度从 0 → 正常尺寸) |
| FadeIn | 淡入(透明度从 0 → 1) |
| SlideInFromLeft | 从左侧滑入 |
| SlideInFromTop | 从顶部滑入 |
| SlideInFromRight | 从右侧滑入 |
| SlideInFromBottom | 从底部滑入 |
Duration:格式为 时:分:秒(如 0:0:0.5 表示 500ms)。

浙公网安备 33010602011771号