Silverlight控件开发讲解.docx
《Silverlight控件开发讲解.docx》由会员分享,可在线阅读,更多相关《Silverlight控件开发讲解.docx(22页珍藏版)》请在冰豆网上搜索。
Silverlight控件开发讲解
Silverlight控件开发
培
训
讲
解
2010-10月byzhlin
第一篇Silverlight控件开发基础
内容提要
&对Silverlight控件开发的认识
&控件开发基础——从样式开始
&模版控件的内部结构分析
&视觉状态的学习
&动画基础
1.1对Silverlight控件开发的认识
在Silverlight中,一切工作都是控件开发。
现从控件开发的角度对Silverlight进行理解,Silverlight的控件分为用户控件、模版控件(或称为自定义控件)两种。
在Silverlight项目开发的过程中,我们可创建的页面有以下几种:
序号
页面模版
中文名称
说明
1
SilverlightUserControl
用户控件
大部分开发使用此页面
2
SilverlightApplicationClass
应用程序入口
3
SilverlightPage
页面
继承自UserControl
4
SilverlightChildWindow
子窗体
继承自ContentControl
5
SilverlightTemplateControl
模版控件
自定义控件
6
SilverlightResourceDictionary
资源字典
样式定义
1、通过SilverlightUserControl创建的页面结构图:
2、通过SilverlightPage创建的页面结构图:
2.1、把鼠标选中Page对象,按F12使用对象浏览器查看Page的类实现图:
3、通过SilverlightChildWindow创建的页面结构图:
3.1、把鼠标选中ChildWindow对象,按F12使用对象浏览器查看ChildWindow的类实现图:
4、通过SilverlightTemplateControl创建的页面结构图:
从上表和创建的页面结构图可以看出,除了应用程序入口和资源字典,在Silverlight项目开发中创建的页面全部是控件,要不是用户控件,要不是模版控件,而资源字典也是为了控件而存在,它负责控件的外观呈现。
其中SilverlightPage只是在继承UserControl的基础上,实现了几个关于页面导航的功能,我们可以把它看成一个实现了页面导航功能的UserControl。
而SilverlightChildWindow是继承自ContentControl,它是一个模版控件,实现了弹出模态子窗体的功能。
为什么在Silverlight项目开发中,创建的页面全是以UserControl的形式存在呢?
对于这个问题,因为Silverlight是一种B/S+C/s相结合的一种应用程序,所以我们既要从Web的角度去看待Silverlight,也要从Winform的角度去看待Silverlight。
从Web的角度看,Silverlight项目没有自己独立的启动程序——即没有提供给操作系统调用的静态入口函数main()函数,是不能直接运行在操作系统上的,它必须依附于Silverlight插件来运行,所以Silverlight应用程序编译生成后,只有一些被打成.xap包的dll,不会有.exe文件输出。
这些dll存储在远程服务端,Silverlight插件把它下载到IE的临时目录,再动态装载运行。
从Winform的角度来看,Silverlight插件是一个Winform的ActiveX控件,我们开发的Silverlight程序是由这个ActiveX控件来加载并运行的,也就是说我们是直接面向这个Winform的ActiveX控件来开发Silverlight程序的,从这个层面来看,我们可以很明显的感觉到开发Silverlight程序如同在开发winform一样,它的运行过程就是ActiveX控件(.net框架环境)——>加载Silverlight用户控件。
Silverlight程序虽然没有提供给操作系统的入口,但它提供给了Silverlight插件的入口——App.cs。
但它不是以静态函数的方式提供的,而是以实例化的方式,在App.cs的构造函数中,注册一个Startup通知事件,用来实例化Silverlight的第一个用户控件。
因为Silverlight插件ActiveX控件内部本身是一个.net框架环境(.net精简框架),所以我们以.net框架开发出来的Silverlight程序可以很好的在里面运行。
在App.cs入口中,RootVisual的类型是UIElement,它是Silverlight控件基类的根,所以:
RootVisual不单可以:
RootVisual=newMainPage();//MainPage是一个用户控件
也可以:
RootVisual=newUserControl();//直接实例化用户控件,正确
RootVisual=newBorder();//直接实例化Border控件,正确
RootVisual=newButton();//直接实例化Button控件,正确
…
正因为Silverlight插件的这种面向控件的特性,所以任意一种在Silverlight中存在的控件,都可以直接实例化给它,并且能够正确地加载和展现出来。
由此可得出结论:
在Silverlight中,一切工作都是控件开发。
1.2控件开发基础——从样式开始
样式决定外观的呈现,先从模版控件的角度来看一下Silverlight样式,之前大家在做的Silverlight开发,都是针对UserControl的,虽然Silverlight把控件划分为模版控件和用户控件,其实UserControl可以看作是模版控件的一个特例,它同样具有模版控件相关的一些特性,同样可以在样式中对UserControl进行类型申明,模版定义,只不过UserControl会经过一些处理,它最终只会显示它的Content中的内容。
所以说,对UserControl页面进行排版的这个过程,说白了,可以看作是对UserControl的内部模版进行一个样式排版。
Silverlight样式的3大要素:
1、类型申明——指定定义的样式应用于什么类型的控件(样式给谁用?
);
2、排版——外观呈现;
3、视觉状态控制——由行为状态控制排版的外观呈现,如鼠标的Normal状态、MouseOver状态、Pressed状态、Disabled状态来控制控件不一样的外观展现。
下面来看一下Silverlight的系统控件Button的样式结构:
因为大家之前做的开发,大多数是对UserControl的开发,所以用得最多的是第2项——排版,控件类型申明和视觉状态控制,在UserControl不是必需的,用得比较少。
现把样式定义的结构体整理成下表:
结构体
用户控件
模版控件
类型申明
不需要
必需
视觉状态
可有可无
可有可无
排版
需要
需要
其中,视觉状态是用于对排版结构体的控制,排版结构体可以一次性排出控件的多个外观版式,再由视觉状态根据不同的行为来控制当前显示哪一个版式。
疑问:
为什么类型申明会出现两次?
那是因为ControlTemplate和Style一样,都是针对类型而定义和应用的,ControlTemplate的定义既可以放在Style里面,也可以作为独立体放到外面进行定义,单独放到外面定义时需要指定Key。
Style既可以指定Key,也可以不指定Key,当Style指定Key时,应用方式如下:
//ButtonStyle为Key名称
当Style没有指定Key时,由定义该样式的应用范围决定,在样式的可见范围之内,所有TargetType类型的控件会全部被应用样式。
Silverlight样式的应用范围:
范围
说明
定义方式
应用程序级
全局可见
在App.xaml中定义:
页面级
在当前页面可见
在UserControl中定义:
控件级
在控件内部可见
样式定义总结:
当你需要对一个控件进行样式定义的时候,应该首先想到样式的3大要素:
类型申明——>排版——>视觉状态控制,这样才能更简单的入手。
1.3模版控件的内部结构分析
控件的内部结构分为外观结构和程序结构,外观结构其实就是控件的整个Style样式定义的结构。
1、熟练掌握Setter属性设置器
在对Style外观结构进行定义的时候,所有属性都是通过Setter属性设置器进行设置的。
2、Setter属性设置器接收的参数
由上图可以看出,就两个参数,一个属性名称,一个属性值。
但这里需要特别注意的是:
它只接受控件的依赖属性进行值设置,而不允许控件的对象属性进行值设置。
3、Silverlight的三种不同类型的属性
a)实例属性
实例属性在以前的开发中,是用得最多的一种属性,无处不在。
b)依赖属性
只有以这种方式定义的属性,才能在Style的样式中进行值设置。
在微软的官方文档中,对依赖属性的功能是这样描述的:
依赖属性支持在样式设置、数据绑定、动画播放、默认值设置、通知事件。
所以,如果你在控件开发的过程中,控件的属性需要支持上述任一项功能,你就必须把它定义为依赖属性,而不是定义为对象属性。
依赖属性的另一项功能是,由于依赖属性是一个静态属性,在层次过多的类继承过程中,大部分属性如背景颜色、字体大小、边框等等的属性,一般只使用默认值就够了,所以即使实例化的对象比较多,它们会共享同一个属性值,在某种程度上来说,有效降低了内存消耗。
c)附加属性
什么是附加属性?
先来看一看大家都使用过的附加属性用例:
也就是说别的控件可以把我这个控件定义的属性来当成他自己的属性一样使用,这样的就是附加属性。
附加属性的好处是自己不需要定义,不需要管理,当需要时,把别人的拿过来用就是。
附加属性的定义和依赖属性一样,也是静态的,由DependencyProperty来进行定义:
d)组合实例属性和依赖属性的方式来进行属性定义
依赖属性虽然在样式设置、数据绑定等等方面的应用中比较方便,但它毕竟是静态属性,而我们在页面创建的控件都是实例,实例是不能访问静态属性的,所以就出现了以实例属性+静态依赖属性组合的方式来进行属性定义:
4、在样式定义中使用TemplateBinding
Setter作为一个属性设置器,它可以设置任意一个依赖属性的值,但如果需要在样式中读取依赖属性的值咧?
那就要使用TemplateBinding,它和Setter的道理一样,只能读取依赖属性的值,不能读取实例属性的值。
读取的方式和数据绑定的方式差不多,如下图:
问题:
由Setter属性设置器设置的依赖属性值和由控件实例设置的依赖属性值,哪个优先级比较高?
设置方式1:
设置方式2:
答案是,不管实例属性设置放在Style设置的前面,还是后面,最后应用到界面上的都是实例属性,这是因为,Style的执行顺序在前面,实例属性的执行顺序在后面。
1.4视觉状态的学习
在Silverlight的系统控件中,任意一个控件,都具有视觉状态。
先通过Blend工具来查看一下系统的Button控件中的视觉状态:
第1步:
在Blend中,拖一个Button控件放在画布上;
第2步:
右键点击Button控件——编辑模版——编辑幅本;
第3步:
在窗口菜单中选中“状态”菜单项,就可以看到对按钮进行定义的视觉状态了。
1.4.1视觉状态的分解:
按照样式的3大要素,从按钮样式的结构中找到视觉状态部分,并对视觉状态进行分解,由此得出视觉状态的组成部分:
1、视觉状态分组:
如视觉状态以组开始,默认为1组。
如视觉状态比较多,可根据需要,把相关的视觉状态进行任意分组,如下表格:
分组名称
视觉状态个体
说明
CommonStates
Normal
普通状态
MouseOver
鼠标经过状态
Pressed
鼠标按下状态
Disabled
禁用状态
FocusStates
Unfocused
失去焦点状态
Focused
获得焦点状态
2、视觉状态个体:
视觉状态个体响应当前的行为,如鼠标或键盘行为;
3、动画控制:
动画控制是对样式3大要素中的排版部分进行动画播放控制。
当控件在屏幕上响应一个行为时,整个流程是:
❶捕获行为状态——>例如:
鼠标经过
❷找到对应的视觉状态个体——>例如:
MouseOver个体
❸触发动画播放——>播放MouseOver个体内部的动画
❹控制排版元素——>例如:
把排版中的背景颜色由深色改成高亮渐变色
❺展现出不同的外观
1.4.2排版部分的分解
排版部分,可以分为默认外观元素,后期外观元素。
一般情况下,没有设置Opacity=0的,或没有设置Visibility=Collapsed的元素为默认外观元素,反之为后期外观元素。
所以排版部分往往看起来比较庞大。
后期外观元素由视觉状态控制动态控制。
此处ContentPresenter在这起到占位符的作用,用来显示嵌套在按钮中的子控件,详细用法将在下一篇介绍。
1.4.3动画是怎么控制排版元素的
动画对排版元素的控制,由两部分组成,第一个是被控制的元素是谁?
第二个是控制元素的什么东西?
熟练掌握两个附加属性:
属性名称
用处
StoryBoard.TargetName
被控制的排版元素名称
StoryBorad.TargetProperty
被控制的排版元素的属性
这两个属性是StoryBoard类的属性,因为是附加属性的原由,所以可以被DoubleAnimation、ColorAnimation等动画元素当成自己的属性来使用。
TargetProperty属性的写法,按照(类型名.属性名).(属性名类型.子属性名)…的规则来书写。
1.5动画基础
1.5.1动画原理:
1、线性插值动画:
由使用者指定3个元素:
a)时间段,b)时间开始处的值、c)时间结束处的值,中间的值由系统通过插值算法进行处理,由此形成一串时间片对应一串值的效果,就形成了动画,例如:
时间长度10秒,宽度属性值:
初始值为0,结束值为100
Width值:
0|___________________________________________|width值100
那么中间的值将由系统根据插值算法得出。
在Silverlight中的运用是这样的:
Storyboard.TargetProperty="Width"
Duration="0:
0:
3"From="0"To="100"/>
对应关系如下表:
a)时间段
Duration="0:
0:
3"
b)时间开始处的值
From="0"
c)时间结束处的值
To="100"
2、关键帧动画:
由使用者指定2个元素:
a)时间戳,b)属性值,每一个时间戳为一帧,使用者通过指定N帧的时间和值,就形成了动画。
例如:
帧
时间戳
值
1
0秒
0
2
0.5秒
20
3
1秒
40
4
1.5秒
60
5
2秒
80
6
2.5秒
100
这个关键帧动画的设计,由2.5秒时间组成了6帧的动画画面,属性值在2.5秒内由0变成了100。
在Silverlight中的运用是这样的:
0:
0"Value="0">
0:
0.5"Value="20">
0:
1"Value="40">
0:
1.5"Value="60">
0:
2"Value="80">
0:
2.5"Value="100">
1.5.2Silverlight中的动画类型
线性插值动画类型:
¦DoubleAnimation:
数值型动画,当你需要控制的属性为数值型时,使用该类型的动画,如宽度、长度、透明值等等。
¦ColorAnimation:
颜色值动画,当你需要控制的属性为颜色值时,使用该类型的动画,如背景,字体颜色。
¦PointAnimation:
位置变化动画,当你需要控制的属性为x,y坐标变化的时候使用该类型的动画,如位置从第1个点point(0,0)移动到第2个点point(100,100)
关键帧动画类型:
在线性插值动画类型的名称前加上UsingKeyFrames即变成了关键帧动画:
¦DoubleAnimationUsingKeyFrames
¦ColorAnimationUsingKeyFrames
¦PointAnimationUsingKeyFrames
帧的类型:
¦线性(linear):
用于数值的控制,变化过程是均匀的。
¦离散(discrete):
用于非数值的控制,无变化过程,直接跳转,如控制属性Visibility的值。
¦多健(splined):
用于数值的控制,变化过程是非均匀的,如加速运动。
1.5.3一个完整动画的组成部分:
⏹故事版:
⏹动画:
由动画控制的元素属性类型决定使用DoubleAnimation、ColorAnimation还是PointAnimation,并指定附加属性StoryBoard.TargetName和StoryBoard.TargetProperty的值,如是插值动画,指定动画时间段Duration、初始值From、结束值To;如果是关键帧动画,则指定KeyTime和Value值即可。
动画
附加属性
需要指定的值
线性插值动画
StoryBoard.TargetName
StoryBoard.TargetProperty
Duration、From、To、By(偏移量可选)
关键帧动画
StoryBoard.TargetName
StoryBoard.TargetProperty
KeyTime、Value
⏹帧:
如是关键帧动画,则需要以帧来完成动画,如是线性插值动画则不需要帧。
完整的线性插值动画示例:
//故事版开始
Storyboard.TargetName="Border"
Storyboard.TargetProperty="Width"
Duration="0"From="0"To="100"/>
//第二个动画,控制背景颜色
Storyboard.TargetName="Border"Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
Duration="0"From="Red"To="Blue"/>
//第三个动画,控制元素的中心点位置
Storyboard.TargetProperty="Center"
Storyboard.TargetName="EllipseGeometry"
Duration="0:
0:
5"From="100,300"To="400,100">
//故事版结束
完整的关键帧动画示例:
//故事版开始
Storyboard.TargetName="Border"
Storyboard.TargetProperty="Width">
0:
0.0"Value="0"/>
0:
0.5"Value="50"/>
0:
1.0"Value="100"/>
//第二个动画,控制背景颜色
Storyboard.TargetName="Border"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
0:
0.0"Value="Red"/>
0:
0.5"Value="Blue"/>
//第三个动画,控制元素的中心点位置