VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#中的样式与模板——统一界面风格

第二部分:桌面应用开发
16.样式与模板——统一界面风格
实例介绍
之前做任务管理工具时,我踩过一个超头疼的坑:界面风格完全乱套——按钮有的是蓝色圆角、有的是灰色方角,输入框边框一会儿粗一会儿细,TaskCard的阴影深浅不一。设计师吐槽“像拼凑的玩具”,我改样式时得一个个找控件,改完按钮改输入框,改完输入框改卡片,半天都搞不定。后来用样式与模板重构,把所有控件的风格统一写在App.xaml里,改一处全vb.net教程C#教程python教程SQL教程access 2010教程局生效,界面瞬间专业了,维护成本直接降了80%。这节就带你用样式与模板给任务管理工具“换皮”,彻底搞定界面统一的痛点。
需求分析
样式与模板要解决的核心问题是“一次定义、全局复用”,具体需求如下:
1.全局统一风格:按钮、输入框、卡片等控件的颜色、形状、字体完全一致;
2.状态响应:控件自动适配交互状态(比如按钮hover时变深、禁用时变灰);
3.可定制性:局部控件可修改样式,不影响全局;
4.主题切换:支持浅色/深色模式,一键切换;
5.数据驱动样式:根据数据状态自动改变UI(比如完成的任务变灰色)。
代码实现
前置条件:.NET 6+、WPF;延续任务管理工具案例,复用TaskItem、TaskCardControl、TaskViewModel。
场景1:全局样式(App.xaml)
全局样式是统一界面的基础,写在App.xaml里,所有控件自动继承。
App.xaml全局样式
xml

	<Application x:Class="TaskManager.App"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	StartupUri="MainWindow.xaml">
	<Application.Resources>
	<!-- 1. 全局颜色资源(方便主题切换) -->
	<SolidColorBrush x:Key="PrimaryColor" Color="#2196F3"/> <!-- 主色:蓝色 -->
	<SolidColorBrush x:Key="SecondaryColor" Color="#F5F5F5"/> <!-- 辅助色:浅灰 -->
	<SolidColorBrush x:Key="TextColor" Color="#333333"/> <!-- 文字色:深灰 -->
	<SolidColorBrush x:Key="DisabledColor" Color="#BDBDBD"/> <!-- 禁用色:中灰 -->
	
	<!-- 2. 按钮全局样式 -->
	<Style TargetType="Button">
	<Setter Property="Background" Value="{DynamicResource PrimaryColor}"/> <!-- 动态资源:支持主题切换 -->
	<Setter Property="Foreground" Value="White"/>
	<Setter Property="BorderThickness" Value="0"/>
	<Setter Property="CornerRadius" Value="4"/> <!-- 圆角 -->
	<Setter Property="Padding" Value="12 6"/> <!-- 内边距 -->
	<Setter Property="FontSize" Value="14"/>
	<Setter Property="Cursor" Value="Hand"/> <!-- 鼠标hover变手型 -->
	
	<!-- 状态触发器 -->
	<Style.Triggers>
	<!-- hover状态:加深主色 -->
	<Trigger Property="IsMouseOver" Value="True">
	<Setter Property="Background" Value="#1976D2"/>
	</Trigger>
	<!-- 禁用状态:变灰色 -->
	<Trigger Property="IsEnabled" Value="False">
	<Setter Property="Background" Value="{DynamicResource DisabledColor}"/>
	<Setter Property="Foreground" Value="#757575"/>
	</Trigger>
	</Style.Triggers>
	</Style>
	
	<!-- 3. 输入框全局样式 -->
	<Style TargetType="TextBox">
	<Setter Property="BorderBrush" Value="#E0E0E0"/>
	<Setter Property="BorderThickness" Value="1"/>
	<Setter Property="CornerRadius" Value="4"/>
	<Setter Property="Padding" Value="8"/>
	<Setter Property="FontSize" Value="14"/>
	
	<Style.Triggers>
	<!-- 获得焦点时:边框变主色 -->
	<Trigger Property="IsFocused" Value="True">
	<Setter Property="BorderBrush" Value="{DynamicResource PrimaryColor}"/>
	<Setter Property="BorderThickness" Value="1.5"/>
	</Trigger>
	</Style.Triggers>
	</Style>
	
	<!-- 4. TaskCardControl全局样式 -->
	<Style TargetType="controls:TaskCardControl">
	<Setter Property="Background" Value="White"/>
	<Setter Property="BorderBrush" Value="#E0E0E0"/>
	<Setter Property="BorderThickness" Value="1"/>
	<Setter Property="CornerRadius" Value="5"/>
	<Setter Property="Margin" Value="5"/>
	
	<Style.Triggers>
	<!-- 已完成任务:灰色背景 -->
	<DataTrigger Binding="{Binding TaskItem.IsCompleted}" Value="True">
	<Setter Property="Background" Value="{DynamicResource SecondaryColor}"/>
	<Setter Property="Opacity" Value="0.8"/>
	</DataTrigger>
	<!-- 过期任务:红色边框 -->
	<DataTrigger Binding="{Binding TaskItem.DueDate, Converter={StaticResource IsOverdueConverter}}" Value="True">
	<Setter Property="BorderBrush" Value="#FF4444"/>
	<Setter Property="BorderThickness" Value="2"/>
	</DataTrigger>
	</Style.Triggers>
	</Style>
	</Application.Resources>
	</Application>

场景2:控件模板(自定义圆形按钮)
控件模板用来重定义控件的结构(比如把按钮改成圆形),替换默认的外观。
自定义圆形按钮模板(App.xaml中添加)
xml

	<!-- 圆形按钮模板 -->
	<ControlTemplate x:Key="CircleButtonTemplate" TargetType="Button">
	<!-- 核心结构:圆形Border + 内容展示器 -->
	<Border 
	CornerRadius="50" <!-- 圆形 -->
	Background="{TemplateBinding Background}" <!-- 绑定按钮自身的Background -->
	BorderBrush="{TemplateBinding BorderBrush}"
	BorderThickness="{TemplateBinding BorderThickness}">
	<!-- ContentPresenter:显示按钮的内容(文字/图标),必须有! -->
	<ContentPresenter 
	HorizontalAlignment="Center" 
	VerticalAlignment="Center" 
	Margin="{TemplateBinding Padding}"/>
	</Border>
	
	<!-- 模板触发器:hover时加深颜色 -->
	<ControlTemplate.Triggers>
	<Trigger Property="IsMouseOver" Value="True">
	<Setter Property="Background" Value="#1976D2"/>
	</Trigger>
	</ControlTemplate.Triggers>
	</ControlTemplate>

使用圆形按钮(MainWindow.xaml)
xml

	<!-- 引用圆形模板的按钮 -->
	<Button Content="+" Width="30" Height="30" 
	Template="{StaticResource CircleButtonTemplate}" 
	Padding="0" Margin="5"/>

场景3:数据模板(ListBox中显示TaskItem)
数据模板用来定义数据对象的显示方式(比如TaskItem在ListBox里的布局)。
ListBox数据模板(MainWindow.xaml)
xml

	<ListBox ItemsSource="{Binding TaskList}" Width="400" Margin="10">
	<ListBox.ItemTemplate>
	<DataTemplate>
	<StackPanel Orientation="Horizontal" Padding="5">
	<!-- 完成状态复选框 -->
	<CheckBox IsChecked="{Binding IsCompleted}" Margin="0 2"/>
	<!-- 任务标题:完成时变灰色 -->
	<TextBlock Text="{Binding Title}" Margin="5 0" VerticalAlignment="Center"
	FontSize="14" Foreground="{DynamicResource TextColor}">
	<TextBlock.Style>
	<Style TargetType="TextBlock">
	<Style.Triggers>
	<DataTrigger Binding="{Binding IsCompleted}" Value="True">
	<Setter Property="Foreground" Value="#999"/>
	<Setter Property="TextDecorations" Value="Strikethrough"/> <!-- 加删除线 -->
	</DataTrigger>
	</Style.Triggers>
	</Style>
	</TextBlock.Style>
	</TextBlock>
	<!-- 截止日期 -->
	<TextBlock Text="{Binding DueDate, StringFormat='yyyy-MM-dd'}" Margin="10 0" 
	FontSize="12" Foreground="#666"/>
	</StackPanel>
	</DataTemplate>
	</ListBox.ItemTemplate>
	</ListBox>

场景4:主题切换(浅色/深色模式)
通过资源字典实现主题切换,一键切换全局颜色。
步骤1:创建主题资源字典
LightTheme.xaml(浅色主题):
xml

	<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
	<SolidColorBrush x:Key="PrimaryColor" Color="#2196F3"/>
	<SolidColorBrush x:Key="SecondaryColor" Color="#F5F5F5"/>
	<SolidColorBrush x:Key="TextColor" Color="#333333"/>
	</ResourceDictionary>

DarkTheme.xaml(深色主题):
xml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<SolidColorBrush x:Key="PrimaryColor" Color="#1976D2"/>
<SolidColorBrush x:Key="SecondaryColor" Color="#333333"/>
<SolidColorBrush x:Key="TextColor" Color="#FFFFFF"/>
</ResourceDictionary>

步骤2:主题切换逻辑(MainWindow.xaml.cs)
csharp

	using System.Windows;
	using System.Windows.Media;
	
	namespace TaskManager
	{
	public partial class MainWindow : Window
	{
	private bool _isDarkTheme = false;
	
	public MainWindow()
	{
	InitializeComponent();
	DataContext = new TaskViewModel();
	}
	
	// 切换主题按钮点击事件
	private void SwitchTheme_Click(object sender, RoutedEventArgs e)
	{
	// 清除现有资源
	Application.Current.Resources.MergedDictionaries.Clear();
	
	// 添加新主题资源
	var themeUri = _isDarkTheme ? "LightTheme.xaml" : "DarkTheme.xaml";
	Application.Current.Resources.MergedDictionaries.Add(
	new ResourceDictionary { Source = new Uri(themeUri, UriKind.Relative) });
	
	// 切换状态
	_isDarkTheme = !_isDarkTheme;
	SwitchThemeBtn.Content = _isDarkTheme ? "浅色模式" : "深色模式";
	}
	}
	}

步骤3:添加主题切换按钮(MainWindow.xaml)
xml

	<Button x:Name="SwitchThemeBtn" Content="深色模式" 
	Click="SwitchTheme_Click" Margin="10"/>

逐行讲解
场景1:全局样式核心逻辑
1.资源定义:定义全局颜色资源,方便主题切换;
2.Style结构:每个Style包含Setter(设置属性)和Trigger(状态触发);
Setter:比如设置按钮背景为全局主色;
Trigger:比如当鼠标hover时,改变按钮背景色;
3.DataTrigger:根据数据状态改变样式,比如当任务完成时,改变卡片背景;
4.DynamicResource:动态资源在运行时解析,支持主题切换(如果用StaticResource,主题切换后不会更新)。
场景2:控件模板核心逻辑
1.ControlTemplate结构:必须包含ContentPresenter(显示控件内容),否则按钮的文字/图标不会显示;
2.TemplateBinding:绑定到控件自身的属性,比如让圆形按钮的背景继承按钮的Background属性,保持灵活性;
3.模板触发器:和Style触发器类似,但作用于模板内的元素。
场景3:数据模板核心逻辑
1.DataTemplate作用:定义数据对象(比如TaskItem)的显示方式,ListBox会自动为每个Item应用这个模板;
2.DataTrigger:根据TaskItem的IsCompleted状态,给文字加删除线和灰色;
3.布局结构:用StackPanel横向排列复选框、标题、日期,保持布局清晰。
场景4:主题切换核心逻辑
1.资源字典切换:通过Application.Current.Resources.MergedDictionaries.Clear()清除现有资源,再添加新的主题资源;
2.动态资源生效:所有样式中使用DynamicResource绑定的属性,会在资源变化时自动更新;
3.状态切换:用_isDarkTheme变量记录当前主题状态,切换按钮文字。
基础知识拓展

  1. Style vs ControlTemplate
特性 Style(样式) ControlTemplate(控件模板)
作用 设置控件属性(颜色、字体、边距等) 重定义控件结构(形状、内部元素)
示例 按钮背景色、圆角 把按钮改成圆形、添加图标
灵活性 局部修改属性 完全替换外观
依赖关系 基于默认模板 不依赖默认模板

总结:Style是“修饰”控件,ControlTemplate是“重构”控件。
2. 静态资源vs动态资源

特性 StaticResource(静态资源) DynamicResource(动态资源)
解析时机 编译时 运行时
性能 更高 略低
适用场景 固定不变的资源(比如固定颜色) 需要动态更新的资源(比如主题切换)

使用方式 {StaticResource PrimaryColor} {DynamicResource PrimaryColor}
关键注意:主题切换必须用DynamicResource!
3. 触发器类型
WPF支持3种常用触发器:
1.PropertyTrigger:控件属性变化触发(比如IsMouseOver、IsFocused);
2.DataTrigger:数据属性变化触发(比如TaskItem.IsCompleted);
3.EventTrigger:事件触发(比如鼠标点击、动画);
示例EventTrigger:按钮点击时播放动画
xml

	<EventTrigger RoutedEvent="Button.Click">
	<BeginStoryboard>
	<Storyboard>
	<DoubleAnimation Storyboard.TargetProperty="Opacity" 
	From="1" To="0.5" Duration="0.2s" 
	AutoReverse="True"/>
	</Storyboard>
	</BeginStoryboard>
	</EventTrigger>
  1. 资源字典组织
    大型项目中,建议把样式按类型拆分到不同的资源字典:
    Buttons.xaml:按钮样式;
    Inputs.xaml:输入框样式;
    Cards.xaml:卡片样式;
    Themes/:主题资源字典;
    然后在App.xaml中合并:
    xml
	<Application.Resources>
	<ResourceDictionary>
	<ResourceDictionary.MergedDictionaries>
	<ResourceDictionary Source="Buttons.xaml"/>
	<ResourceDictionary Source="Inputs.xaml"/>
	<ResourceDictionary Source="Themes/LightTheme.xaml"/>
	</ResourceDictionary.MergedDictionaries>
	</ResourceDictionary>
	</Application.Resources>

总结
样式与模板是WPF中统一界面风格的核心,掌握后可以:
1.全局统一:改一处样式,所有控件同步更新;
2.动态切换:一键切换浅色/深色主题;
3.状态响应:自动适配交互状态(hover、禁用、完成等);
4.复用性高:避免重复写样式,提高开发效率;
比如任务管理工具中,全局样式让按钮、输入框、卡片风格一致,主题切换只需切换资源字典,数据模板让任务列表显示更美观。掌握这些技巧,你的界面会更专业,维护成本会更低。

本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49463.html


相关教程