《Programming WPF》翻译 第6章 2.资源与样式

简介: 原文:《Programming WPF》翻译 第6章 2.资源与样式WPF的样式机制以来于资源体系来定位样式。正如你在第5章看到的,样式在元素的资源片段中定义,而且样式通过其名字被引用,正如示例6-18所示: 示例6-18                                                 Hello     然而,如何定义一个样式,使之自动的应用到一个元素,而无需显示指定要引用的资源——这是可以实现的,而且非常有用——当你需要把一个样式应用到具有独特类型的所有元素上,而不是把资源引用添加到每个元素上。
原文: 《Programming WPF》翻译 第6章 2.资源与样式

WPF的样式机制以来于资源体系来定位样式。正如你在第5章看到的,样式在元素的资源片段中定义,而且样式通过其名字被引用,正如示例6-18所示:

示例6-18

< Window  x:Class ="ResourcePlay.Window1"  Text ="ResourcePlay"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005" >

    
< Window.Resources >
        
< Style  x:Key ="myStyle" >
            
< Setter  Property ="Button.FontSize"  Value ="36"   />
        
</ Style >
    
</ Window.Resources >

    
< Grid >
        
< Button  Style =" {StaticResource myStyle} " > Hello </ Button >
    
</ Grid >
</ Window >

然而,如何定义一个样式,使之自动的应用到一个元素,而无需显示指定要引用的资源——这是可以实现的,而且非常有用——当你需要把一个样式应用到具有独特类型的所有元素上,而不是把资源引用添加到每个元素上。示例

6-19 对示例6-18 做了一些修改,展示了隐式声明这一功能。

示例6-19

< Window  x:Class ="ResourcePlay.Window1"  Text ="ResourcePlay"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005" >

    
< Window.Resources >
        
< Style  TargetType =" {x:Type Button} " >
            
< Setter  Property ="Button.FontSize"  Value ="36"   />
        
</ Style >
    
</ Window.Resources >

    
< Grid >
        
< Button > Hello </ Button >
    
</ Grid >
</ Window >

注意到

Button 标签不再有其特定的Style 属性。然而,这个样式仍然通过TargetType 应用到Button 上,而不是定义一个key ,这个样式使用x:Type 来设置TargetType ,于是通知XAML 为这个TargetType 类提供一个System.Type 对象。

如果FrameworkElement没有显示指定Style,它总是会寻找一个使用其自身类型的样式资源,作为其Target类型。

如果你建立了一些非样式的资源,例如SolidColorBrush,同时设置其x:Key为某个UI元素的类型,如果试着使用该元素的类型就会发生一个错误。这是因为你创建了一个带有TargetTypeStyle却没有指定x:Keyx:Key隐式地设置为同TargetType一样。这个Key用于定位style。因此,通常而言,你应该避免将x:Key设置为Type类型的对象。

因为元素会在资源中搜索它的样式,你可以利用系统级别的资源。你可以定义一个样式资源在局部范围内,如果你仅仅希望影响少量的元素;或者在一个广义范围上,例如
Window.Resource;或者在应用程序的范围。而且样式可能延及到系统级别。这种样式和资源之间的联系是使用皮肤和主体的关键

6.2.1皮肤和主题

皮肤和主题都是控制UI外观的技术。主题,是一种系统级别的外观,例如Windows2000的经典外观,又如Windows XP的“Luna”主题。皮肤是一个特定于应用程序的外观,正如各种各样具有不同样式的媒体播放程序,例如WinAppWindows Media Player

皮肤和主题都可以在WPF实现,作为一组资源应用于需要该样式的控件

既然皮肤的意图在于控制一个特定应用程序的外观,它将为标准控件提供更多的样式,可以在应用程序的指定部分定义各种各样有命名的资源。例如,音乐播放器可能使用一个ListBox用来显示歌曲列表。皮肤可以为之提供一个特定的外观而不用影响应用程序中其他的ListBox。因此应用程序可以为这个ListBox设置特定的命名的样式,同时要在这个样式中支持这个样式。对于这种特定情形,提供这样一个样式是可选择的,但是在其他情形中,应用程序需要皮肤提供提供指定的资源。例如,如果应用程序中有一个工具条,皮肤可能就需要提供资源并在其中为这个工具条定义图像。

同样,主体是用于所有应用程序,因此,其必须为所有类型的控件提供模板和样式。比较而言,一个皮肤是特定于应用程序的,所以它不必提供广泛全面的一组样式。如果应用程序并不使用每一个单独的控件类型,皮肤只需要为那些在应用程序中出现的控件提供样式。示例6-20和示例6-21为一个相当简单的皮肤,展示了xaml和相应的后台代码

示例6-20

<ResourceDictionary x:Class="SimpleSkin.BlueSkin"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005"
    
>
    
<Style TargetType="{x:Type Button}">
        
<Setter Property="Background" Value="Blue" />
        
<Setter Property="Foreground" Value="White" />
    
</Style>
</ResourceDictionary>

示例 6-21

using System;
using System.Windows;

namespace SimpleSkin {

    
public partial class BlueSkin : ResourceDictionary {

        
public BlueSkin( ) {
            InitializeComponent( );
        }

    }

}

以上代码为一个按钮设置了前景色和背景色。一个更复杂的皮肤应该可以为更多的类型元素提供样式,并且提供更多的属性。更多的皮肤包括一些模板属性的设定,从而可以定义控件的外观。但是即使是在这个简单的例子中,底层的原理也都是一样的。示例6-22展示了一个UI,示例6-23则是这个UI的相应后台代码,允许皮肤的切换。(这个示例假设有2个皮肤类,BlueSkinGreenSkin,都是使用示例6-20的技术定义的。

示例6-22

<Window x:Class="SimpleSkin.Window1" Text="SimpleSkin"
    xmlns
="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x
="http://schemas.microsoft.com/winfx/xaml/2005">

    
<Grid Margin="1">
        
<Grid.RowDefinitions>
            
<RowDefinition Height="Auto" />
            
<RowDefinition Height="Auto" />
        
</Grid.RowDefinitions>

        
<RadioButtonList x:Name="radioSkins">
            
<TextBlock>Green</TextBlock>
            
<TextBlock>Blue</TextBlock>
        
</RadioButtonList>

        
<Button Grid.Row="1">Hello</Button>
    
</Grid>
</Window>

示例

6-23

using System;
using System.Windows;
using System.Windows.Controls;

namespace SimpleSkin {

    
public partial class Window1 : Window {

        
public Window1( ) {
            InitializeComponent( );

            EnsureSkins( );

            radioSkins.SelectionChanged 
+= SkinChanged;
        }


        
static ResourceDictionary greenSkin;
        
static ResourceDictionary blueSkin;
        
static bool resourcesLoaded = false;

        
private static void EnsureSkins( ) {
            
if (!resourcesLoaded) {
                greenSkin 
= new GreenSkin( );
                blueSkin 
= new BlueSkin( );

                resourcesLoaded 
= true;
            }

        }


        
private void SkinChanged(object o, SelectionChangedEventArgs e) {
            
switch (radioSkins.SelectedIndex) {
                
case 0:
                    Application.Current.Resources 
= greenSkin;
                    
break;
                
case 1:
                    Application.Current.Resources 
= blueSkin;
                    
break;
            }

        }

    }

}

SimpleSkin 类的代码确保了皮肤只创建一次,而且简单地更换皮肤——通过设置应用程序资源字典,使之成为选中的皮肤。(第二个皮肤的源GreenSkin ,在这里没有显示出来,看上去和示例6-20 相同,只是用绿色取代了蓝色。)样式和系统资源随着资源的更换自动反映出来:当更改皮肤的时候更新所有有效的控件,因此,这就是我们需要的代码。图6-5 显示了代码效果。

6-5


这种切换皮肤的方式有一个小障碍。除了使用皮肤资源,在应用程序级别也存储了一些资源,那么这些应用程序资源会在切换皮肤时丢失。现在,唯一的解决方案是保证每一个皮肤包含一份应用程序级别的资源副本。最好的办法是将这些副本保存在一个单独的类,并将副本和并到资源皮肤中。
WPF当前的版本不支持自动和并资源字典,WPF团队的成员已经声明,他们正在考虑更容易的处理办法在未来的发布版本中。目前,只能手动处理,正如示例6-24所示。

示例6-24

ResourceDictionary skinResources  =   new  FooSkinResources( );
ResourceDictionary nonSkinAppResources 
=   new  DrawingResources( );

foreach  (DictionaryEntry de  in  nonSkinAppResources)  {
    skinResources.Add(de.Key, de.Value);
}

如上,你可以将代码添加到加载资源的方法中。

在示例6-23 中,你可以在EnsureSkins 方法中和并资源,将blue green 皮肤都和并到nonSkinAppResources 中。

目录
相关文章
|
10月前
|
C#
WPF疑难问题之Treeview中HierarchicalDataTemplate多级样式
WPF疑难问题之Treeview中HierarchicalDataTemplate多级样式
201 0
|
29天前
|
文字识别 C# 开发者
WPF开源的一款免费、开箱即用的翻译、OCR工具
WPF开源的一款免费、开箱即用的翻译、OCR工具
|
29天前
|
C#
浅谈WPF之样式与资源
WPF通过样式,不仅可以方便的设置控件元素的展示方式,给用户呈现多样化的体验,还简化配置,避免重复设置元素的属性,以达到节约成本,提高工作效率的目的,样式也是资源的一种表现形式。本文以一个简单的小例子,简述如何设置WPF的样式以及资源的应用,仅供学习分享使用,如有不足之处,还请指正。
57 0
|
10月前
WPF-布局样式练习-Day02-聊天气泡
WPF-布局样式练习-Day02-聊天气泡
152 1
|
10月前
|
C#
WPF-Binding问题-模板样式使用Binding TemplatedParent与TemplateBinding区别
WPF-Binding问题-模板样式使用Binding TemplatedParent与TemplateBinding区别
110 0
|
10月前
WPF-样式问题-处理ListBox、ListView子项内容全填充问题
WPF-样式问题-处理ListBox、ListView子项内容全填充问题
132 0
|
10月前
|
C#
WPF-布局样式练习-Day01
WPF-布局样式练习-Day01
86 0
|
29天前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
104 0
|
29天前
|
C#
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
77 1
|
10月前
|
C# Windows
WPF技术之图形系列Polygon控件
WPF Polygon是Windows Presentation Foundation (WPF)框架中的一个标记元素,用于绘制多边形形状。它可以通过设置多个点的坐标来定义多边形的形状,可以绘制任意复杂度的多边形。
543 0