WPF中的Style(风格,样式)

                                                                             WPF中的Style(风格,样式)
                                                                                                            周银辉

在WPF中我们可以使用Style来设置控件的某些属性值,并使该设置影响到指定范围内的所有该类控件或影响指定的某一控件,比如说我们想将窗口中的所有按钮都保持某一种风格,那么我们可以设置一个Style,而不必分别设置每个按钮的风格。

Style是作为一种资源被保存下来的. 看下面的例子:
 <Window.Resources>   
    
<Style TargetType="Button">
      
<Setter Property="Foreground"  Value="Blue"/>
      
<Setter Property="FontFamily " Value="CourierNew"/>
    
</Style>      
 
</Window.Resources>
我们声明了一个Style,它被声明在Window.Resources中说明它的有效范围是当前窗体,TargetType="Button" 指示该Style的作用对象是Button类的实例,也就是说在当前窗体中的所有Button实例都将受到该Style的影响(除非某Button有明确地指明它所使用的是另外的Style)。
<Setter Property="Foreground"  Value="Blue"/> 这里的Setter是一个设置器,用来设置该Style要对TargetType的那些属性或对象进行设置,我们这里设置的是Button的Foreground属性,将其值设置为Blue,同理,我们将Button的FontFamily属性设置为CourierNew

这样一来,在默认情况下,被加载到窗口中的所有Button对象都将受到这个Style的影响,从而文本变成统一的蓝色CourierNew字体。
你可以粘贴以下代码到XamlPad中查看效果:
<Window 
    
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
="StyleDemo" Height="417" Width="579"
    
>
  
  
  
<Window.Resources>    
    
<Style TargetType="Button">
      
<Setter Property="Foreground"  Value="Blue"/>
      
<Setter Property="FontFamily " Value="CourierNew"/>
    
</Style>       
  
</Window.Resources>
  
  
    
<Grid ShowGridLines="True">
      
      
<Grid.ColumnDefinitions>
        
<ColumnDefinition  Width="50*"/>
        
<ColumnDefinition Width="50*" />
      
</Grid.ColumnDefinitions>
      
<Grid.RowDefinitions>
        
<RowDefinition  Height="25*"/>
        
<RowDefinition  Height="25*"/>
        
<RowDefinition  Height="25*"/>
      
</Grid.RowDefinitions>

      
<Button Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Grid.RowSpan="1">button1</Button>
      
<Button Grid.Column="2" Grid.ColumnSpan="1" Grid.Row="1" Grid.RowSpan="1">button2</Button>
     
    
</Grid>
  
</Window>


接下来很容易想到的一个问题是,想上述代码的强制窗口的所有按钮都受声明的Style的影响是不是有点强奸民意,如果我只想我定义的Style影响指定的Button对象而不是所有的Button对象应该怎么办呢?
参考以下代码:我们为Style添加一个x:Key="ButtonStyle"

  <Window.Resources>
    
    
<Style TargetType="Button" x:Key="ButtonStyle">
      
<Setter Property="Foreground"  Value="Blue"/>
      
<Setter Property="FontFamily " Value="CourierNew"/>
    
</Style>
        
  
</Window.Resources>

然后我们使用Button的Style属性来指定该Button所要使用的Style,而其他没有将我们声明的Style指定为其样式的按钮将不受到该Style的影响。
<Button>normal button</Button>
<Button Style="{StaticResource ButtonStyle}">styled button</Button>
这样就很好的解决了Style强制影响每个Button的问题,你可以粘贴以下代码到XamlPad中查看效果:
<Window 
    
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
="StyleDemo" Height="417" Width="579"
    
>
  
  
  
<Window.Resources>   
    
<Style TargetType="Button" x:Key="ButtonStyle">
      
<Setter Property="Foreground"  Value="Blue"/>
      
<Setter Property="FontFamily " Value="CourierNew"/>
    
</Style>    
  
</Window.Resources>
  
  
    
<Grid ShowGridLines="True">
      
      
<Grid.ColumnDefinitions>
        
<ColumnDefinition  Width="50*"/>
        
<ColumnDefinition Width="50*" />
      
</Grid.ColumnDefinitions>
      
<Grid.RowDefinitions>
        
<RowDefinition  Height="25*"/>
        
<RowDefinition  Height="25*"/>
        
<RowDefinition  Height="25*"/>
      
</Grid.RowDefinitions>

      
<Button Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Grid.RowSpan="1">normal button</Button>
      
<Button Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="1" Grid.RowSpan="1" Style="{StaticResource ButtonStyle}">styled button1</Button>
      
<Button Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="2" Grid.RowSpan="1" Style="{StaticResource ButtonStyle}">styled button2</Button>
    
    
</Grid>
  
</Window>


为了让我们的Style对外界的交互做出外观上的相应,比如当鼠标按下时蓝色的文本变成红色,当鼠标松开时文本又恢复蓝色,我们可以在Style中添加Trigger(触发器),除此之外,与类的继承原理相类似,我们还可以使用BaseOn来使一个Style“继承”另一个Style。
参考以下代码:
 <Window.Resources>
    
    
<Style TargetType="Button" x:Key="ButtonStyle">
      
<Setter Property="Foreground"  Value="Blue"/>
      
<Setter Property="FontFamily " Value="CourierNew"/>
    
</Style>
    
    
<Style TargetType="Button" x:Key="TriggerButtonStyle" BasedOn="{StaticResource ButtonStyle}">
      
<Style.Triggers>
        
<Trigger  Property="IsPressed" Value="True">
          
<Setter Property="Foreground" Value="Red"/>
        
</Trigger>
      
</Style.Triggers>
    
</Style>
    
  
</Window.Resources>
我们所声明的第二个Style,即TriggerButtonStyle,它“继承”于ButtonStyle,那么TriggerButtonStyle将会从ButtonStyle那里得到蓝色CourierNew文本的性质。然后我们使用了Trigger来响应鼠标按下,  <Trigger  Property="IsPressed" Value="True"> 表示当Button的IsPressed属性值变为True的时候,将做如下设置<Setter Property="Foreground" Value="Red"/>,即将Button的Foreground属性设置为Red。这里有一个隐含的意思是:当当Button的IsPressed属性值变为False的时候,Foreground属性将恢复原值。
你可以粘贴以下代码到XamlPad中查看效果:
<Window 
    
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
="StyleDemo" Height="417" Width="579"
    
>
  
  
  
<Window.Resources>
    
    
<Style TargetType="Button" x:Key="ButtonStyle">
      
<Setter Property="Foreground"  Value="Blue"/>
      
<Setter Property="FontFamily " Value="CourierNew"/>
    
</Style>
    
    
<Style TargetType="Button" x:Key="TriggerButtonStyle" BasedOn="{StaticResource ButtonStyle}">
      
<Style.Triggers>
        
<Trigger  Property="IsPressed" Value="True">
          
<Setter Property="Foreground" Value="Red"/>
        
</Trigger>
      
</Style.Triggers>
    
</Style>
    
  
</Window.Resources>
  
  
    
<Grid ShowGridLines="True">
      
      
<Grid.ColumnDefinitions>
        
<ColumnDefinition  Width="50*"/>
        
<ColumnDefinition Width="50*" />
      
</Grid.ColumnDefinitions>
      
<Grid.RowDefinitions>
        
<RowDefinition  Height="25*"/>
        
<RowDefinition  Height="25*"/>
        
<RowDefinition  Height="25*"/>
      
</Grid.RowDefinitions>

      
<Button Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Grid.RowSpan="1">normal button</Button>
      
<Button Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="1" Grid.RowSpan="1" Style="{StaticResource ButtonStyle}">styled button</Button>
      
<Button Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="2" Grid.RowSpan="1" Style="{StaticResource TriggerButtonStyle}">trigger button</Button>
    
    
</Grid>
  
</Window>
0
0
(请您对文章做出评价)
« 上一篇:[转] 使用模板自定义 WPF 控件
» 下一篇:WPF中的ControlTemplate(控件模板)
posted @ 2007-03-27 20:10 周银辉 阅读(5642) 评论(20)  编辑 收藏 网摘 所属分类: WPF

  回复  引用  查看    
#1楼2007-03-27 21:14 | Cat Chen      
看起来比CSS要复杂得多,又是“1.0并不好用”的例子,等2.0再看看吧。
  回复  引用  查看    
#2楼[楼主]2007-03-27 21:22 | 周银辉      
我开始,其实就是在几天前,也挺讨厌XAML的,但现在开始有些喜欢了,因为在编写UI方面它的确比C#或其他程序设计语言更灵活与快捷
  回复  引用  查看    
#3楼2007-03-27 21:36 | JesseZhao      
微软的东西等到第三个版本再用吧
感觉那样就不错了

  回复  引用  查看    
#4楼2007-03-27 23:35 | Sheva      
to Cat Chen
很多人一开始特别喜欢拿HTML/CSS和XAML进行比较,XAML的Style语法从很多角度上看要比CSS的更合理,更简捷。
起初的时候微软就象把CSS的语法引入到XAML里面去来定义样式,但是最后他们发现这样一来他们就给XAML进入了一种新的语法,一种和XML不兼容的语法,这样就给他们编写XAML分析器带来了很多的困难,而且从开发人员的角度上看,一种编程进行进入太多的语法不是一件好事,这种弄会给开发人员带来更大的负担。
但是这些都还好,最终微软放弃CSS语法是因为XAML的样式所要支持的东西比CSS更广泛,XAML的Triggers用CSS就不可能实现。所以最终微软开始决定此阿用一种兼容XML的样式申明格式。所以XAML其实就是XML,它没有引入什么新的标识语法。这其实是一件好事。
但是WPF的样式也要问题的时候,我今天就发现了一个Bug,我的这篇post里面有详尽的说明:
http://shevaspace.spaces.live.com/blog/cns!FD9A0F1F8DD06954!548.entry

Sheva

  回复  引用  查看    
#5楼2007-03-27 23:59 | Artech      
好像是把Style当成一种Resource。还可以通过BasedOn继承另一个Style。
通过TargetType指定目标控件的类型(这点好像和Skin的原理类似)。通过引用Resource的方式把Style 运用到具体的控件中。

一种全新的模式,不错。

  回复  引用  查看    
#6楼2007-03-28 01:03 | Cat Chen      
@Sheva
我也明白XML的好处,但是从书写得容易程度来说……除非提供全程IntelliSense,否则这样写肯定比应该描述的内容多了很多字符,所以我觉得提供一种类似CSS的书写方式会更好。

  回复  引用    
#7楼2007-03-28 08:55 | zhouyinhui
VS2005装了插件Visual Studio 2005 Extensions for WCF, WPF后,IntelliSense很好用的
  回复  引用  查看    
#8楼2007-03-28 09:36 | Leepy      
@周银辉
能不能提供个插件Visual Studio 2005 Extensions for WPF 的 下载地址,我搜不到!谢谢了

  回复  引用  查看    
#10楼2007-03-28 11:16 | Leepy      
@zhouyinhui
谢谢了:)
不过好象打不开啊:(
插件大不大啊?能否发个邮件给我?sunleepy@gmail.com

  回复  引用    
#11楼2007-03-28 11:27 | ququ[未注册用户]
To zhouyinhui
你好:

问一个题外话,在表格中,行和列的定义,
<ColumnDefinition Width="50*"/>的50后面带*是什么意思,我只知道,如果是窗口的一半用0.5*,剩余部分用*,那么50*是不是和窗口宽度一半有关系呢?还有,行高,为什么也是25*,到底什么意思呢?
新手,请指教!

  回复  引用  查看    
#12楼[楼主]2007-03-28 11:43 | 周银辉      
TO: ququ
指定表格的大小时,可以有三种方式:
1,GridUnitType.Auto:自动,其大小取决于其内容(Content)的大小,在Xaml中你可以这样书写<ColumnDefinition Width="Auto" />
2,GridUnitType.Star:按比例,比如<ColumnDefinition Width="50*"/>表示该列占据整个表格宽度的50%
3GridUnitType.Pixel:表示指定的值为像素数。在Xaml中你可以这样书写<ColumnDefinition Width="50"/>

  回复  引用  查看    
#13楼2007-03-28 12:31 | Yiling Lai      
@周银辉 & ququ

关于*的解释我认为是有问题的,的确是按照百分比来的,但是50*并不一定表示50%。假设其中一个设置为50*,另一个设置30*,那么第一个的宽度占的比例应该是:50/(30+50)。

  回复  引用    
#14楼2007-03-28 13:20 | zhouyinhui
Member name Description
Auto, The size is determined by the size properties of the content object.
Pixel,The value is expressed as a pixel.
Star, The value is expressed as a weighted proportion of available space.
===================================
Remarks
Star sizing is used to distribute available space by weighted proportions. For additional information about this type of sizing, see Use Star Sizing.

In Extensible Application Markup Language (XAML), star values are expressed as * or 2*. In the first case, the row or column would receive one times the available space; in the second case, the row or column would receive two times the available space, and so on.


  回复  引用  查看    
#15楼2007-04-22 20:21 | 曲滨      
有很多人想歪了
XAML 在ms 的设计上就不是开发的程序员来用的东西
xaml 是给 界面设计人员的,而且有对应的一套类似 Adobe 套件的工具

就像做 flash 那样做出来的。

要不一点点写 xaml 即使 IntelliSense 在强也写的很郁闷。

  回复  引用  查看    
#16楼2007-04-22 20:23 | 曲滨      
不过国内好像,很多公司没有专门的 ui 设计人员
而导致如果程序员要学WPF 就要学习 xaml 和 对应的类库
2套语言哎,郁闷啊

  回复  引用  查看    
#17楼[楼主]2007-07-08 15:56 | 周银辉      
关于GridLength中的*:

When a row’s height or column’s width is set to *, it occupies all the remaining
space.
. When multiple rows or columns use *, the remaining space is divided equally
between them.
. Rows and columns can place a coefficient in front of the asterisk (like 2* or 5.5*) to
take proportionately more space than other columns using the asterisk notation. A
column with width 2* is always twice the width of a column with width * (which is
shorthand for 1*) in the same Grid. A column with width 5.5* is always twice the
width of a column with width 2.75* in the same Grid.

  回复  引用    
#18楼2007-08-16 17:12 | 在线代理[未注册用户]
里面的animation实在有点烦 。
没有很好的类比,不像这个style和css里面的style还是有点像

  回复  引用  查看    
#19楼2009-11-27 18:20 | Taven.李锡远      
内容对我很有用啊 WPF是个好东西,谁用谁知道