3.WPF资源字典和模板

目的:定义样式、模板等可复用的资源

1. 定义与引用资源(元素级 / 窗口级 / 应用级)

窗口级示例:只有本窗口可以使用

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Resource Demo">
    <!-- 窗口级资源 -->
    <Window.Resources>
        <!-- 定义画笔资源 -->
        <SolidColorBrush x:Key="RedBrush" Color="Red"/>
        <!-- 定义样式资源 -->
        <Style x:Key="ButtonStyle" TargetType="Button">
            <Setter Property="Background" Value="{StaticResource RedBrush}"/>
            <Setter Property="Foreground" Value="White"/>
        </Style>
    </Window.Resources>

    <!-- 引用资源 -->
    <Button Style="{StaticResource ButtonStyle}" Content="Click Me"/>
</Window>

应用级资源(在App.xaml中定义,全应用可调用)下面这个示例

<Application x:Class="WpfApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <SolidColorBrush x:Key="AppLevelBrush" Color="Blue"/>
    </Application.Resources>
</Application>

 

 

外部资源字典(独立 XAML 文件)将资源放在单独的.xaml文件中,通过MergedDictionaries合并,实现资源复用和解耦。

这个是外部文件资源字典

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style x:Key="TextBlockStyle" TargetType="TextBlock">
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Margin" Value="5"/>
    </Style>
</ResourceDictionary>

定义了外部资源必须要使用,就要合并资源

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <!-- 合并外部资源字典 -->
            <ResourceDictionary Source="Styles.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <!-- 可添加当前级别的资源 -->
        <SolidColorBrush x:Key="LocalBrush" Color="Green"/>
    </ResourceDictionary>
</Window.Resources>

<!-- 引用外部资源 -->
<TextBlock Style="{StaticResource TextBlockStyle}" Text="Hello"/>

下面动态资源示例,利用MVVM方式的,MVVM代码就不展示了,所谓动态资源就是,能够在后代代码中随时改变的值,可以是动态绑定的属性值,也可以是动态绑定的字典比如xxx.xaml

<Window.Resources>
    <!-- 背景色资源 绑定的值,在后台代码中会改变-->
    <SolidColorBrush x:Key="BgBrush" Color="{Binding BackgroundColor}"/>
    <!-- 文本颜色资源 -->
    <SolidColorBrush x:Key="TextBrush" Color="{Binding TextColor}"/>
    <!-- 字体大小资源,这里double没法绑定 -->
    
    <sys:Double x:Key="DefaultFontSize" >14</sys:Double>
</Window.Resources>

<StackPanel Background="{DynamicResource BgBrush}" Margin="10">
    <TextBlock Text="MVVM动态资源示例" 
               Foreground="{DynamicResource TextBrush}" 
               Margin="5"/>

    <Button Content="切换到深色主题" 
            Command="{Binding SwitchToDarkThemeCommand}"
            Margin="5"
            Padding="10,5"/>

    <Button Content="切换到浅色主题" 
            Command="{Binding SwitchToLightThemeCommand}"
            Margin="5"
            Padding="10,5"/>
    <Button Content="恢复默认设置" 
            Command="{Binding ResetDefaultsCommand}"
            Margin="5"
            Padding="10,5"/>
</StackPanel>

 

资源的本地化(多语言支持)

也是属性动态资源,需要在后台代码中调整App资源加载的文件名称,下面是一个例子

image3个语言文件

image这个就展示一个英语的,其它的不展示

 

<Application x:Class="资源字典_语言切换.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:资源字典_语言切换"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <!-- 默认加载(合并)英文资源 -->
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/Strings.en.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

在APPxaml中默认加载英文的,在APP的cs文件中这个方法,可以改变加载的文件名,面板就可以任意切换语言了

using System.Windows;

namespace 资源字典_语言切换
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public static void ChangeLanguage(string languageCode)
        {
            // 清除现有资源
            Current.Resources.MergedDictionaries.Clear();

            // 根据语言代码加载对应的资源字典
            string resourcePath = $"Resources/Strings.{languageCode}.xaml";
            var resourceDict = new ResourceDictionary
            {
                Source = new Uri(resourcePath, UriKind.Relative)
            };

            Current.Resources.MergedDictionaries.Add(resourceDict);
        }
    }

}

我们的主界面代码绑定的话,如下只是其中一个,可多个控件绑定多个资源属性。

<TextBlock Text="{DynamicResource WelcomeMessage}" FontSize="24" FontWeight="Bold"/>

 

资源也可以在代码中添加删除操作,如下

// 获取应用级资源字典
var appResources = Application.Current.Resources;

// 添加资源
appResources.Add("DynamicBrush", new SolidColorBrush(Colors.Orange));

// 修改资源
if (appResources.Contains("RedBrush"))
{
    appResources["RedBrush"] = new SolidColorBrush(Colors.DarkRed);
}

// 删除资源
appResources.Remove("OldBrush");

// 读取资源
var brush = appResources["DynamicBrush"] as SolidColorBrush;

 

 

3. 资源查找顺序

WPF 查找资源时遵循 “就近原则”,顺序为:
 
  1. 元素自身的Resources
  2. 父元素的Resources(向上递归)
  3. 窗口 / 页面的Resources
  4. 应用程序的ResourcesApp.xaml
  5. 系统资源(如SystemColors

 

下面这个XAML 下表示所有的按钮只要没指定key,默认都会是这个样式,因为窗口资源已定义好

<Window x:Class="HeBianGuTest.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:HeBianGuTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
            <Setter Property="Padding" Value="10,6" />
            <Setter Property="Background" Value="Blue"/>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions >
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button Content="A" Grid.Row="0"/>
        <Button Content="B" Grid.Row="1"/>
        <Button Content="C" Grid.Row="2"/>
        <Button Content="D" Grid.Row="3"/>
    </Grid>
</Window>
View Code

 

 

资源与触发器结合

<ResourceDictionary>
    <SolidColorBrush x:Key="NormalBrush" Color="Gray"/>
    <SolidColorBrush x:Key="HoverBrush" Color="Blue"/>

    <Style TargetType="Button">
        <Setter Property="Background" Value="{StaticResource NormalBrush}"/>
        <Style.Triggers>
            <!-- 鼠标悬停时切换资源 -->
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Background" Value="{StaticResource HoverBrush}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</ResourceDictionary>

共享大型资源(如图片、字体)

对于占用内存较大的资源(如BitmapImageFontFamily),通过资源字典共享可避免重复创建,优化性能。

<ResourceDictionary>
    <!-- 共享图片资源 -->
    <BitmapImage x:Key="LogoImage" UriSource="Images/logo.png" CacheOption="OnLoad"/>
    <!-- 共享字体资源 -->
    <FontFamily x:Key="CustomFont" Source="Fonts/#Roboto"/>
</ResourceDictionary>

 

 

  • 样式是 “给控件的属性化妆”(不改骨架);
  • 模板是 “给控件换骨架”(或定义数据的展示方式)。

一下是简单的数据模板示例

cs

using System.Collections.Generic;
using System.Windows;

namespace SimpleDataTemplateDemo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this; // 设置窗口自身为数据上下文
            People = new List<Person>
            {
                new Person { Name = "张三", Age = 25 },
                new Person { Name = "李四", Age = 30 },
                new Person { Name = "王五", Age = 35 }
            };
        }

        public List<Person> People { get; set; }
    }

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

xaml

<Window x:Class="SimpleDataTemplateDemo.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:SimpleDataTemplateDemo"
        mc:Ignorable="d"
        Title="简单 DataTemplate 示例" Height="200" Width="300">
    <Window.Resources>
        <!-- 定义基础数据模板 -->
        <DataTemplate x:Key="PersonTemplate">
            <StackPanel Orientation="Horizontal" Margin="5">
                <Ellipse Width="40" Height="40" Fill="LightBlue" Margin="0 0 10 0" />
                <StackPanel>
                    <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                    <TextBlock Text="{Binding Age, StringFormat='年龄: {0}'}" Foreground="Gray" />
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <!--数据源是People属性,数据模板是PersonTemplate-->
    <ListBox ItemsSource="{Binding People}" ItemTemplate="{StaticResource PersonTemplate}"/>
</Window>

 

  •  

posted @ 2025-04-17 08:07  灰色淡季  阅读(62)  评论(0)    收藏  举报