原文:《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元素的类型,如果试着使用该元素的类型就会发生一个错误。这是因为你创建了一个带有TargetType的Style却没有指定x:Key,x:Key隐式地设置为同TargetType一样。这个Key用于定位style。因此,通常而言,你应该避免将x:Key设置为Type类型的对象。



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

6.2.1皮肤和主题

皮肤和主题都是控制UI外观的技术。主题,是一种系统级别的外观,例如Windows2000的经典外观,又如Windows XP的“Luna”主题。皮肤是一个特定于应用程序的外观,正如各种各样具有不同样式的媒体播放程序,例如WinApp和Windows 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个皮肤类,BlueSkin和GreenSkin,都是使用示例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) {

                :

                    Application.Current.Resources = greenSkin;

                    break;

                :

                    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中。

《Programming WPF》翻译 第6章 2.资源与样式的更多相关文章

  1. 《Programming WPF》翻译 第5章 4.元素类型样式

    原文:<Programming WPF>翻译 第5章 4.元素类型样式 命名样式非常有用,当你得到一组属性并应用到特点的元素上.然而,如果你想要应用一个统一的样式到所有确定元素类型的实例, ...

  2. 《Programming WPF》翻译 第5章 2.内嵌样式

    原文:<Programming WPF>翻译 第5章 2.内嵌样式 每一个“可样式化”的WPF元素都有一个Style属性,可以在内部设置这个属性--使用XAML属性-元素的语法(在第一章讨 ...

  3. 《Programming WPF》翻译 第5章 1.不使用样式

    原文:<Programming WPF>翻译 第5章 1.不使用样式 作为一个样式如何使其在WPF使用的例子,,让我们看一下TTT简单的实现,如示例5-1. 示例5-1 <!-- W ...

  4. 《Programming WPF》翻译 第6章 3.二进制资源

    原文:<Programming WPF>翻译 第6章 3.二进制资源 尽管ResourceDictionary和系统级别的资源适合于作为数据存在于对象中,然而,并不是所有的资源都能很好的满 ...

  5. 《Programming WPF》翻译 第6章 1.创建和使用资源

    原文:<Programming WPF>翻译 第6章 1.创建和使用资源 资源这个词具有非常广泛的意义.任何对象都可以是一个资源.一个在用户界面中经常使用的Brush或者Color可以是一 ...

  6. 《Programming WPF》翻译 第9章 5.默认可视化

    原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...

  7. 《Programming WPF》翻译 第7章 3.笔刷和钢笔

    原文:<Programming WPF>翻译 第7章 3.笔刷和钢笔 为了在屏幕上绘制一个图形,WPF需要知道你想要为图形填充什么颜色以及如何绘制它的边框.WPF提供了一些Brush类型支 ...

  8. 《Programming WPF》翻译 第6章 5.我们进行到哪里了?

    原文:<Programming WPF>翻译 第6章 5.我们进行到哪里了? WPF提供了资源工具,让我们运用在用户界面中,动态并具有一致性.我们可以在资源字典中存储任意资源,并且可以遍及 ...

  9. 《Programming WPF》翻译 第6章 4.应用程序全球化

    原文:<Programming WPF>翻译 第6章 4.应用程序全球化 如果你打算发布你的应用程序到全球各地,你可能需要为不同地区的用户界面准备不同的版本.至少,这需要解决将文本翻译成适 ...

随机推荐

  1. 外部函数接口 LibFFI

    “FFI” 的全名是 Foreign Function Interface,通常指的是允许以一种语言编写的代码调用另一种语言的代码.而 “Libffi” 库只提供了最底层的.与架构相关的.完整的”FF ...

  2. Ushare应用

    Ushare应用 Openwrt 系统功能强大,主要优势在于其开放性和可扩展性,Openwrt 安装ushare后,可将路由器变身为一个功能强大的家庭upnp流媒体服务器! 打开网上邻居,会显示发现u ...

  3. Android ToggleButton使用介绍

    ToggleButton,就是开关按钮,包括选中和未选中状态,并且需要为不同的状态设置不同的事件处理: 例如:使用图片来展示ToggleButton不同的状态: MainActivity.java p ...

  4. 利用linux信号机制调试段错误(Segment fault)

    在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...

  5. OpenXML - 如何导出List<DataModel>到Excel -- Part 1

    最近这几天研究OpenXML: 这是Open XML的一些介绍: Open XML 介绍:http://baike.baidu.com/view/1201978.htm 下载:http://www.m ...

  6. Android SDK及ADT更新访问问题的解决办法

    一.访问问题Eclipse使用SDK Manager更新时总是出现问题 Failed to fetch URL https://dl-ssl.google.com/android/repository ...

  7. Android仿IOS回弹效果 ScrollView回弹 总结

    Android仿IOS回弹效果  ScrollView回弹 总结 应项目中的需求  须要仿IOS 下拉回弹的效果 , 我在网上搜了非常多 大多数都是拿scrollview 改吧改吧 试了一些  发现总 ...

  8. 使用android-resource-remover删除项目中无用的资源,减少包的大小

    写这篇文章的原因是,一个CSDN的资源链接,Android程序员必备精品资源,在该链接的实用工具集锦中有一个工具吸引了我的注意,那就是android-resource-remover,它的解释是:一个 ...

  9. 执行curl -sSL 提示curl: (35) SSL connect error

    今天,添加容器节点报错,执行如下 curl -sSL https://shipyard-project.com/deploy| ACTION=node DISCOVERY=etcd://192.168 ...

  10. 高可用集群(HA)配置

    高可用集群(HA) 1. 准备工作 HA的心跳监测可以通过串口连接监测也可以通过网线监测,前者需要服务器有一个串口,后者需要有一个空闲网卡.HA架构中需要有一个共享的存储设备首先需要在两台机器上安装m ...