注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

分享,态度 ·~~

—— 十年太长,五年;如果可以回到五年前,你最想对那时候的自己说什么?

 
 
 

日志

 
 

样式、模板和触发器之间的联系  

2009-09-06 23:23:03|  分类: DotNet |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

7.3.4  样式、模板和触发器之间的联系

到现在为止,本书已经基本完成了对Style的介绍。Style、Template和Trigger都是通过对适合条件的更改来完成属性值的控制。对一个属性的设置可以出现在许多不同的地方。例如,在Style的Trigger中,在Style本身之中以及在Template的Trigger中。如果这三处都对一个属性进行设置,那么最终该属性会选取哪个设置呢?在WPF中,在Style的Trigger中对属性进行设置将导致Template的Trigger对属性的设置失效,而所有的Trigger将覆盖所有在Style中对属性的设置。

或许有读者要问:既然控件模板和样式都可以完成对用户某些行为的响应,而且它们的功能也基本相同,那么是不是它们对触发器的实现也完全相同呢?在前面介绍ControlTemplate类的Trigger属性时已经提到过,控件模板中的触发器对属性的设置是对视觉树节点进行修改的过程,而样式对Setter的使用实际上是对控件实例本身的属性进行修改。下面的例子中,后台代码通过OnPropertyChanged函数侦听PropertyChanged消息来证明控件模板对控件外观的修改实际上并没有修改控件实例本身的属性值,而只是修改了视觉树,其代码如下所示。

<Window …
xmlns:local="clr-namespace:XXX">
<Window.Resources>
<ControlTemplate TargetType="{x:Type Button}" x:Key="template">
<Border Background="{TemplateBinding Background}" x:Name="border">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red" TargetName="border"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="style" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<local:PropertyButton Template="{StaticResource
template}" Content="template change"/>
<local:PropertyButton Style="{StaticResource style}
" Content="template change"/>
</StackPanel>
</Window>





与该段代码相对应的侦听属性变化的代码如下所示:

……
public class PropertyButton : System.Windows.Controls.Button
{
public PropertyButton()
: base()
{
}
 protected override void OnPropertyChanged
(DependencyPropertyChangedEventArgs args)
{
if (args.Property == Button.BackgroundProperty)
{
MessageBox.Show("Background changed!");
}
  base.OnPropertyChanged(args);
}
}
……

运行该段程序可以看到,当用户的鼠标移到第一个控件之上时,示例程序并没有任何消息框弹出。鼠标移上按钮时的背景为红色是因为控件模板对外观的更改是在视觉树中进行的,并没有影响控件的属性。而当用户将鼠标移到第二个按钮之上时,由于Style对视觉效果的改变是通过更改属性来完成的,因此该行为会导致PropertyChanged消息的发出,触发对OnPropertyChanged函数的调用。在OnPropertyChanged函数中,后台代码通过传入的参数args记录的信息判断Button类的BackgroundProperty是否发生了改变。如果是,程序将弹出一个对话框,通知用户按钮的背景颜色属性已经被更改。在本程序中,由于对话框的弹出将导致主窗口失去焦点,因此按钮的IsMouseOver属性在对话框弹出时立即恢复为false。这也是鼠标移到第二个按钮上时按钮的背景颜色并没有更改,而背景颜色更改的提示消息框出现了两次的原因。

从以往的编程经验中,人们总结出了面向对象编程中所需要的MVC(model - view - controller)模型。该模型也是WPF中各个控件设计的根本思路。该思路并不是通过其他内容而是本节所讲述的样式和模板体现的。

在MVC模型中,一个具有独立逻辑功能的对象由三个部分组成:Model,即数据和功能,也就是界面所需要展示的数据以及其逻辑功能;View,即界面显示部分;Controller,即界面与数据之间的沟通。

那么首先想想自定义的数据应该怎样在WPF程序中显示。在WPF所提供的可行的办法中,最简单的办法就是通过数据模板(DataTemplate)。也就是说,数据模板实现的是从数据到界面元素之间的转化,即Controller的功能,同时,它还可以对用户所执行的操作进行一些简单的响应。

但是模板只是对视觉树中的节点进行更改,并不对实际属性进行修改。因此样式在一定程度上起到了界面元素对属性修改的功能,虽然该功能具有许多限制。

在一个程序中,软件界面常常需要通过界面元素对数据进行显示。比如使用列表框控件对数据集合中的各个数据进行显示,或者使用树控件显示可嵌套命令以及参数之间的树型关系等(读者可以简单地想象程序中的函数调用)。对于这些数据的处理,软件开发人员先需要想清楚它们是什么样的关系。如果是一种并列的数据集合,那么他就可以选择使用列表框(ListBox)对它们进行显示,而使用列表项(ListBoxItem)对数据项进行显示;如果是一种树型数据集合,那么他就需要使用树控件(TreeView),数据的显示是通过树节点(TreeViewItem)对数据项进行表示的。在确定了数据之间的关系后,不论是使用ListBoxItem还是使用TreeViewItem,软件开发人员都需要为它们要显示的数据定义一种模板,并赋给ItemsTemplate属性,否则,就需要通过编写代码对数据的各个属性进行修改。这样,一方面增加了错误的可能性,另一方面则增加了数据结构更改时对显示逻辑更改的难度。最后,软件开发人员还需要对数据更改这种情况进行考虑。通常情况下,ListBox和TreeView总是将ItemsSource属性与某一个数据源进行绑定以设置其所需要显示的内容。可如果只将数据源与ItemsSource属性进行绑定,而在模板中没有对界面显示的各个属性进行绑定,则对数据中的某个数据项的更改并不会导致程序的刷新。因此在理想的解决方案中,软件开发人员需要将可能更改的数据项与界面元素的某个属性进行绑定。当然,软件开发人员也可以选择不对它们进行绑定,只需要得到绑定的BindingExpression实例并调用它的UpdateTarget函数就可以完成对数据显示的刷新。但是该方法的缺点是性能损失太大。因此,建议读者在对绑定这一方法了解足够深刻的条件下尽量将数据中各个属性与显示它们的界面元素进行绑定。当然,为了获得对绑定的支持,软件开发人员不仅可以选择从INotifyPropertyChanged接口派生,还可以通过后面将要讲解的通过DependencyProperty的Register函数在属性系统中注册属性来完成。关于绑定本书已经在第6章中讲过了,不再赘述。

【from 《WPF全视角分析》 http://book.51cto.com/art/200906/127979.htm

  评论这张
 
阅读(680)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017