原文:《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. Qt自定义sleep延时函数(巧妙的使用时间差,但这样似乎CPU满格,而不是沉睡)

    Qt不像VC++的win32/MFC编程那样,提供了现成的sleep函数可供调用.Qt把sleep函数封装在QThread类中.子线程可以调用sleep函数.但是如果用户想在主线程实现延时功能,该怎么 ...

  2. 转:使用linq to sql 随机取一行数据的方法

    原文地址:http://outofmemory.cn/code-snippet/1760/usage-linq-to-sql-suiji-take-yixing-data-method 虽然这看来已经 ...

  3. cf492C Vanya and Exams

    C. Vanya and Exams time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  4. 《Unix环境高级编程》环境搭建

    用的是第三版的安装包:src.3e.tar.gz 地址:http://www.apuebook.com/ 1.解压:$ tar  -zxvf  *.tar.gz 2. $ cd apue.3e/ 3. ...

  5. pager-taglib 使用说明2

    传两个值进去:1.pm.totles总记录数 2.pagesize 每页显示页数 3.<pg:param name="parentId"/>传给后台的变量值对(查询条件 ...

  6. mac复制粘贴剪切

    win下复制粘贴剪切: Ctrl+C,Ctrl+V,Ctrl+X; mac下lion之后已经有了一直让win用户吐槽的剪切功能: 复制粘贴剪切:Command+C,Command+V,Command+ ...

  7. c语言学习之结构篇代码演示样例-输入n个同学的姓名,数学英语成绩,依照平均分从低到高排序并输出

    #include<stdio.h> void main(){ const int count = 5;//定义数量 struct student{ char name[80]; float ...

  8. 除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。

    在 SELECT 后加 TOP 100 PERCENT .

  9. MVC 路由Router

    Url路由将进入的请求发送给控制器操作. url路由使用路由表处理进入的请求 此路由表在应用程序第一次启动时创建. 路由表在Global.asax文件中设置

  10. Key lock 的秘密

    研究死锁,或者观察sp_lock,有时候最恼人的莫过于你看到下面研究成果的key lock,但是却不知道究竟是哪个page 哪个row被lock住了: Exec sp_lock:   就说上面的key ...