原文:《Programming WPF》翻译 第5章 3.命名属性

通过把同样的内嵌样式提升到资源中(正如第一章介绍的),我们可以给它一个名字,以及按名字使用它在我们的Button实例上,正如示例5-5。

示例5-5

<!-- Window1.xaml -->

<Window >



  <Window.Resources>

    <Style x:Key="CellTextStyle">

      <Setter Property="Control.FontSize" Value="32" />

      <Setter Property="Control.FontWeight" Value="Bold" />

    </Style>

  </Window.Resources>

  

  <Button Style="{StaticResource CellTextStyle}"  x:Name="cell00" />

  

</Window>

在示例5-5中,我们在属性中使用到Control前缀取代Button前缀,从而允许样式更广泛的应用,正如我们将要看到的。

5.3.1 TargetType属性

方便起见,如果所有的属性可以在一个共享类中设置,像我们示例中的Control,我们可以提升这个类的前缀,放入TargetType属性中,并将其从属性的名称中移除掉。如示例5-6所示。

示例5-6

<Style x:Key="CellTextStyle" TargetType="{x:Type Control}">

  <Setter Property="FontSize" Value="32" />

  <Setter Property="FontWeight" Value="Bold" />

</Style>

当提供了一个TargetType属性,你能够只设置该类型可接受的属性。如果你想要在继承树下扩展一组大量的属性,你可以通过使用一个派生类型来做到这些,如示例5-7。

示例5-7

<Style x:Key="CellTextStyle" TargetType="{x:Type Button}">



  <!-- IsCancel is a Button-specific property -->

  <Setter Property="IsCancel" Value="False" />

  <Setter Property="FontSize" Value="32" />

  <Setter Property="FontWeight" Value="Bold" />

</Style>

在这种情形中,IsCancel属性只在Button上有效,因此,为了设置它,我们需要为了这个类型转换TargetType属性。

你可能想知道为什么我设置FontSize为“32”而不是“32pt”,当详细的指定了字体大小时,后者在一条直线上占得更多,。这两种表示法明显是不相等的。(前者是pixels,而后者是points)。由于这种写法,我使用pixels,WPF样式使用了一个不加前缀的属性,允许“32pt”明确指定为FontSize,然而前缀属性并不是这样。例如,下面的代码能正常运行(假设Target已经被设置了):

    <Setter Property=”FontSize” Value=”32pt” />

而以下并没有这么做(不管TargetType是否被设定)

    <Setter Property=”Control.FontSize” Value=”32pt” />

希望在你读到这里的时候,这个问题已经被修复了。(而且没有被其它所取代)

5.3.2样式复用

除了将你从要为每一个属性名输出类前缀的名称解救出来之外,TargetType属性还会检查所有应用了样式的类是那个类型或派生的类型的一个实例。这意味着一旦我们将TargetType在Control中设置,我们就能将其应用到一个Button元素,而不是一个TextBlock元素,前者最终派生于Control,而后者不是。

另一方面,尽管Control和TextBlock都共享共同的FrameworkElement祖先,FrameworkElement并没有定义一个FontSize依赖属性,因此一个带有FrameworkElement.TargetType的样式不会让我们设置FontSize属性,因为它并不在那里,尽管事实上Control和TextBlock都有一个FontSize属性。

即使在Control中设置TargetType,我们获得了一个跨越类来复用样式的尺度,这些类是派生于Control的,如Button,Label,Window等等。尽管如此,如果我们从样式中一起去除TargetType属性,我们获得了一个跨越控件来复用样式的尺度,不再有一个公有的基础,而是共享一个依赖属性的实现。根据我的经验,我发现依赖属性跨越类共享了同样的名称,如Control.FontSize和TextBlock.FontSize,还共享了一个实现。这意味着即使Control和TextBlock各自定义了它们的FontSize属性,在运行时它们共享这个属性的实现,所以我可以编写示例5-8那样的代码。

示例5-8



<Style x:Key="CellTextStyle">

  <Setter Property="Control.FontSize" Value="32" />

</Style>



<!-- derives from Control -->

<Button Style="{StaticResource CellTextStyle}"  />



<!-- does *not* derive from Control -->

<TextBlock Style="{StaticResource CellTextStyle}"  />

在示例5-8中,我从样式定义中去除了TargetType属性,使用了替代的雷前缀在每个样式设置的属性上。这个样式能被应用到一个Button元素,正如你期望的,也能应用到一个TextBlock控件上,随着FontSize在样式中明确地设定。这样工作的原因是Button从Control获取它的FontSize依赖属性定义,而TextBlock,提供它的FontSize依赖属性定义,共享由TextElement实现的FontSize依赖属性。图5-2显示了元素间的关系及他们的依赖属性实现。

如图5-2所示,如果我们需要,我们可以按照TextElement重新定义我们的样式,即使它陷入机成熟,既不是Control也不是TextBlock,如示例5-9所示。

图5-2





示例5-9

<Style x:Key="CellTextStyle">

  <Setter Property="TextElement.FontSize" Value="32" />

</Style>



<Button Style="{StaticResource CellTextStyle}"  />

<TextBlock Style="{StaticResource CellTextStyle}"  />

更进一步,如果我们想要定义一个包含属性的样式,这些属性没有被每个我们要应用样式的元素共享,我们也可以这么做,如示例5-10。

示例5-10

<Style x:Key="CellTextStyle">

  <Setter Property="TextElement.FontSize" Value="32" />

  <Setter Property="Button.IsCancel" Value="False" />

</Style>



<!-- has an IsCancel property -->

<Button Style="{StaticResource CellTextStyle}"  />



<!-- does *not* have an IsCancel property -->

<TextBlock Style="{StaticResource CellTextStyle}"  />

在示例5-10中,我们已经添加了Button.IsCancel属性在CellTextStyle中,以及将其应用到有这个属性的Button元素,而TextBlock元素则没有这个属性。那好,在运行时,WPF将应用依赖属性到拥有这个属性的元素上

WPF的应用样式到对象的能力,并不要求对象有所有的属性定义在样式中,类似的应用到Word的Normal样式,包含一个字体类型属性,同时包括一段文本和一个图片。即使Word知道图片没有字体类型,它仍然应用到Normal样式的一部分使之确实有意义。(正如对齐属性),忽略其余的内容。

回到我们的示例,我们可以在一个新行中的TextBlock上使用CellTextStyle,以显示轮到谁了,如示例5-11所示:



示例5-11:

<Window.Resources>

  <Style x:Key="CellTextStyle">

    <Setter Property="TextElement.FontSize" Value="32" />

    <Setter Property="TextElement.FontWeight" Value="Bold" />

  </Style>

</Window.Resources>

<Grid Background="Black">

  <Grid.RowDefinitions>

    <RowDefinition />

    <RowDefinition />

    <RowDefinition />

    <RowDefinition Height="Auto" />

  </Grid.RowDefinitions>

  <Grid.ColumnDefinitions>

    <ColumnDefinition />

    <ColumnDefinition />

    <ColumnDefinition />

  </Grid.ColumnDefinitions>

  <Button Style="{StaticResource CellTextStyle}"  />

  

  <TextBlock

    Style="{StaticResource CellTextStyle}"

    

    Foreground="White"

    Grid.Row="3"

    Grid.ColumnSpan="3"

    x:Name="statusTextBlock" />

</Grid>

</Window>

跨越不同控件的样式复用给我的应用程序一致的外观,如图5-3所示。

你应该注意的是图5-3的状态文字,尽管按钮中的文字是黑色的。由于黑色是默认的文字颜色,如果我们想要状态文字的显示相对于黑色背景,我们不得不将颜色改变为其它,因此需要在TextBlock上设置Foreground属性为白色。联合样式,每一个示例属性Setting都工作正常,而且,你可以联合两种设置属性值的技术正如你看到的。

图5-3





5.3.3

进一步,如果我们想要在一个指定的实例上复写一个样式属性,通过在实例上设置属性,我们是可以做到的,正如示例5-12。

示例5-12

<Style x:Key="CellTextStyle">

  <Setter Property="TextElement.FontSize" Value="32" />

  <Setter Property="TextElement.FontWeight" Value="Bold" />

</Style>



<TextBlock

  Style="{StaticResource CellTextStyle}"

  FontWeight="Thin"  />

在示例5-12中,在TextBlock实例属性上设置FontWeight,优先于在样式属性上设置FontWeight。

5.3.4继承样式属性

为了完成oo的三个特征:复用,复写,继承,你可以从一个基础样式继承一个样式,添加新属性或者重写已有属性,如示例5-13所示。

示例5-13

<Style x:Key="CellTextStyle">

  <Setter Property="TextElement.FontSize" Value="32" />

  <Setter Property="TextElement.FontWeight" Value="Bold" />

</Style>

<Style x:Key="StatusTextStyle" BasedOn="{StaticResource CellTextStyle}">

  <Setter Property="TextElement.FontWeight" Value="Thin" />

  <Setter Property="TextElement.Foreground" Value="White" />

  <Setter Property="TextBlock.HorizontalAlignment" Value="Center" />

</Style>

BaseOn样式属性用于指定一个基础样式。在示例5-3中,StatusTextStyle样式继承了所有CellTextStyle属性的设置,复写了FontWeight,以及Foreground和HorizontalAlignment的设置。注意到,HorizontalAlignment属性使用了TextBlock前缀,这是因为TextElement没有HorizontalAlignment这个属性。

我们当前使用的样式了引起了TTT游戏看上去如图5-4。

图5-4





到目前为止,我们的应用程序相当不错,尤其是状态文字上的细字体宽度,但是我们可以做得更好。

5.3.5编程上设置样式

一旦一个样式有了名字,从我们的代码中是很好利用的。例如,我们可能决定要每个玩家有自己的样式。在这种情形中,在xaml中,在编译期使用命名属性不会成功,因为我们想基于内容设置样式,而内容是直到运行期才知道的。然而,没有什么要求我们去设置一个控件静态的Style属性;我们也可以编程实现,如示例5-14。

示例5-14

public partial class Window1 : Window {

  void cell_Click(object sender, RoutedEventArgs e) {

    Button button = (Button)sender;

    

    // Set button content

    button.Content = this.CurrentPlayer;

    

    if( this.CurrentPlayer == "X" ) {

      button.Style = (Style)FindResource("XStyle");

      this.CurrentPlayer == "O";

    }

    else {

      button.Style = (Style)FindResource("OStyle");

      this.CurrentPlayer == "X";

    }

    

  }

  

}

在示例5-14中,无论玩家何时点击,除了设置按钮内容之外,我们从窗体资源中拉出一个命名样式并将其设置给按钮的样式。这假设了一对命名样式在窗体级别被定义,如示例5-15。

示例5-15

<Window.Resources>

  <Style x:Key="CellTextStyle">

    <Setter Property="TextElement.FontSize" Value="32" />

    <Setter Property="TextElement.FontWeight" Value="Bold" />

  </Style>

  <Style x:Key="XStyle" BasedOn="{StaticResource CellTextStyle}">

    <Setter Property="TextElement.Foreground" Value="Red" />

  

  </Style>

  <Style x:Key="OStyle" BasedOn="{StaticResource CellTextStyle}">

    <Setter Property="TextElement.Foreground" Value="Green" />

  </Style>

</Window.Resources>

随着这些适当位置的样式,以及伴随着内容的设置按钮样式的代码,我们得到图5-5。

注意到,所有的X和O都根据命名玩家的样式设置了颜色。在这种特定的情形中(以及其他情形),数据触发器(在5.6中讨论)应该被优先选择用来以编程方式设置样式,但是你不知道什么时候将要必须去堵塞。

作为所有xaml的构造器,你可以自由地以编程方式创建样式。附录A是一个好的介绍——关于如何考虑在xaml和代码之间来来往往的进行。

图5-5





《Programming WPF》翻译 第5章 3.命名属性的更多相关文章

  1. 《Programming WPF》翻译 第8章 4.关键帧动画

    原文:<Programming WPF>翻译 第8章 4.关键帧动画 到目前为止,我们只看到简单的点到点的动画.我们使用了To和From属性或者By属性来设计动画--相对于当前的属性值.这 ...

  2. 《Programming WPF》翻译 第8章 2.Timeline

    原文:<Programming WPF>翻译 第8章 2.Timeline Timeline代表了时间的延伸.它通常还描述了一个或多个在这段时间所发生的事情.例如,在前面章节描述的动画类型 ...

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

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

  4. 《Programming WPF》翻译 第7章 2.图形

    原文:<Programming WPF>翻译 第7章 2.图形 图形时绘图的基础,代表用户界面树的元素.WPF支持多种不同的形状,并为它们每一个都提供了元素类型. 7.2.1基本图形类 在 ...

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

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

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

    原文:<Programming WPF>翻译 第6章 2.资源与样式 WPF的样式机制以来于资源体系来定位样式.正如你在第5章看到的,样式在元素的资源片段中定义,而且样式通过其名字被引用, ...

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

    原文:<Programming WPF>翻译 第5章 8.我们进行到哪里了? 样式支持你定义一个策略来设置可视化元素的依赖属性.属性的设置可以被命名以及手动或者编程方式地通过名称应用,或者 ...

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

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

  9. 《Programming WPF》翻译 第5章 6.触发器

    原文:<Programming WPF>翻译 第5章 6.触发器 目前为止,我们已经看到样式,作为一个Setter元素的集合.当应用一个样式时,在Setter元素中描述的设置不会无条件地应 ...

随机推荐

  1. list append 总是复制前面的参数,而不复制最后一个参数

    append 总是复制前面的参数,而不复制最后一个参数 (define a1 '(1 2 3)) (define a2 '(a b c)) (define x (append a1 a2)) x ; ...

  2. jquery判断checkbox是否选中

    $('input:checkbox').click(function () { if ($("#chkPile").is(":checked")) { $(); ...

  3. java开发经验分享(四)

    四. 关于测试 1. 在整个项目计划中,测试时间安排的合理性,对测试阶段的情况应作充分预计,不可为了赶发布点而忽略质量. 2. 务必清楚产品包.更新包.bug包的提交规范.具体请参照<开发规范手 ...

  4. ZZY的宠物

    Description ZZY领养了一对刚刚出生的不知名小宠物..巨萌巨可爱!!...小宠物的生命为5个单位时间并且不会在中间出意外翘辫子(如: 从0出生能活到5但活不到6)..小宠物经过2个单位时间 ...

  5. Linux CentOS 7 YouCompleteMe相关配置。

    CentOS 6.5上面弄了2天,以失败告终!!!当作练手了.在网上看到一篇CentOS7.0上安装YouCompleteMe插件的文章,就重新在虚拟机上安装了一个CentOS7,按那个文章执行了一下 ...

  6. join 数据库

    早上随手拿了本数据库的书,看到关于join的,想到很久之前妹妹(妹妹离职了,好桑感)发给我的一个简单浅显易懂的关于这方面的网页,所以翻出来瞅瞅,贴出来与大家共享之. http://coolshell. ...

  7. Spring 小示例

    通过一个简单的示例来初步理解Spring框架 1.创建java工程,导入相应Spring包,放在lib文件夹中 2.接口  IHelloMessage package com.jike.spring. ...

  8. js基础例子

    创建变量 var obj=value; 其中obj是变量名; value表示可能是数字,数组,函数之类的 多变量进行计算 var a1=200,b1='hello',c1=400; var d1=c1 ...

  9. .NET--接口设计

    我们学习.net视频的时候,老师讲的是"介面设计",有意思的是,这里的介面不是我们想象中的界面的意思,而是接口的意思. 由于视频是Micorsoft公司做的,所以整个视频看下来.仅 ...

  10. Web Api 跨域解决方案

    一.跨域问题的由来 同源策略:出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容. 正是由于这个原因,我们不同项目之间的调用就会被浏览器阻 ...