您的位置:首页 > 业界新闻

学习WPF,转向移动互联网(windows phone && windows 8 )开发(上)

2012-07-24 14:36 453 查看
做了两年的WPF开发,主要参与开发水利、铁路、广播电视、电力行业的监控项目,总的来说WPF做这类项目,还是有一手的,我本人使用的也比较得心应手。因一直关注着移动互联网的发展,今年年初从原公司辞职,转向移动互联网方向,现从事windows移动方面的开发,上班几个月来,感觉还行,由于做了两年的WPF,转windows phone、windows 8,还比较顺利,独立开发的第一个应用已经上线,心情愉悦。现对WPF的几个技术要点做下总结(关于WPF的简介什么的在这就不做总结,这类的文章比较多),希望对大家有帮助。

一、 几个关键类

l System.Threading.DispatcherObject

WPF 中的大多数对象是从 DispatcherObject 派生的,这提供了用于处理并发和线程的基本构造。 WPF 基于调度程序实现的消息系统。其工作方式与常见的 Win32 消息泵非常类似;事实上,WPF 调度程序使用 User32 消息执行跨线程调用。Wpf为单线程模型,把整个用户界面将被宿主到单一的线程。

l System.Windows.DependencyObject

WPF主要通过属性与界面交互,提供一套强大是属性系统,并使用声明式的编程语法。该属性系统是从 DependencyObject 类型派生的。

l System.Windows.Media.Visual

Visual 类用于生成可视化对象的树,可以看成一个图形对象,WPF中呈现的每个元素都是一个可视化的对象。

l System.Windows.UIElement

UIElement 定义核心子系统,包括 Layout、Input 和 Event。引入了增强的事件传递系统,路由事件。

l System.Windows.FrameworkElemen

关于应用程序布局,并引入了两个新的概念 数据绑定和样式,数据绑定最值得关注的功能是 数据模板

l System.Windows.Controls.Control

添加了一些属性,字体、前景色,提供对控件模板的支持,开发人员可以使用自定义样式改变控件的标准呈现

Control —FrameworkElement—UIElement—Visual(从左至右继承)

二、 视觉树和逻辑树

l 逻辑树为对象树,可提供开发人员变成遍历、扩充、以及编程修改用户界面。LogicalTreeHelper有了逻辑树的存在,内容模型可以方便地循环访问其潜在子对象,因而可以得到扩展。资源通过逻辑树查找

l 视觉树为的组成界面的各个元素,呈现用户界面,当修改控件外观、编写模板时使用。路由事件的事件路由特性大多数遍历可视化树。

三、 ResourceDictionary

l 资源字典 是使用键值对来存储资源(Resource)

l 资源的作用就近原则

l 资源合并

四、 属性变更通知

l INotifyPropertyChange(System.ComponentModel

向客户端发出某一属性值更改的通知。PropertyChanged

l ObservableCollection<T>类,它是实现 INotifyCollectionChanged 接口的数据集合的内置实现。

表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知

五、 Commands (命令)作用和好处

l 减少业务代码与UI的耦合度。

l Command可以集中管理不同操作。

l Command既和操作关联,又和界面关联。

六、 Routed Events(路由事件)

l 定义

WPF提供了一套新的事件处理系统—路由事件

定义:事件按照指定的线路进行传递的机制。

l 与CLR事件的区别

CLR事件,可以与一个或多个元素相关联,但是每个关联的元素需要显示进行订阅事件,否则CLR将忽略该对象。

WPF路由事件提供一中不同的机制,路由事件可在WPF元素树上进行向上或向下的传递,无论元素是否关联订阅,位于元素树上下级事件都有机会处理事件。

l WPF使用路由事件的原因

WPF这中事件传递机制,与其内容模型有密切关联Eg:一个button的content属性赋值一image副图片,当输入事件产生时,比如用户点击button按钮,,会产生一个click事件,这是image也要处理鼠标事件,如果按照CLR事件处理的话,那意味着开发人员需要同时订阅image和button的事件。目前button的内容是一个简单的元素树结构,还可以接受,如果是一个非常复杂的元素树结构,那需要订阅的事件就非常可观啦,非常复杂。

用途

1、 定义公用处理程序、组合自己的控件或者自定义控件类。

2、 应用程序间的不同元素交换信息。

3、 元素树上的元素通信。

l 事件路由策略

u 冒泡(bubble):事件源先调用事件处理程序,然后沿着元素树向上传递到父元素,一直到元素树的根。(事件源—>根元素)

u 直接(direct):事件只在被附加事件的元素上触发,并不会传递给其他元素。支持类处理机制,可以用在EventSetter and EventTrigger

u 隧道(tunnel):根元素先调用事件处理程序,然后沿着元素树向下传递,一直到事件源元素。

(根元素—>事件源)。隧道事件以Preview标示开始。

七、 依赖属性

什么是依赖属性

WPF使用一组服务(属性赋值的规则,包括属性变更回调(PropertyChangedCallback)、强制值回调(CoerceValueCallback)、属性验证回调(ValidateValueCallback)、计算、验证、限制)对CLR属性进行扩展,这个服务叫做属性系统,属性系统支持的属性为依赖属性。

实例:

View Code

1 public class SimpleDO : DependencyObject
2 {
3 public static readonly DependencyProperty ValueProperty =
4 DependencyProperty.Register("Value", typeof(double), typeof(SimpleDO),
5 new FrameworkPropertyMetadata((double)0.0,
6 FrameworkPropertyMetadataOptions.None,
7 new PropertyChangedCallback(OnValueChanged),
8 new CoerceValueCallback(CoerceValue)),
9 new ValidateValueCallback(IsValidateValue));
10
11 public double Value
12 {
13 get { return (double)GetValue(ValueProperty); }
14 set { SetValue(ValueProperty, value); }
15 }
16
17 private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
18 {
19 Console.WriteLine("ValueChanged new value is {0}", e.NewValue);
20 }
21
22 private static object CoerceValue(DependencyObject d, object value)
23 {
24 Console.WriteLine("CoerceValue value is {0}", value);
25 return value;
26 }
27
28 private static bool IsValidateValue(object value)
29 {
30 Console.WriteLine("ValidateValue value is {0}", value);
31 return true;
32 }
33 }

与.NET属性有什么不同

l 定义方式,依赖属性DependcyObject无public的方法,避免实例化,这就需要依赖属性采用一种注册的方式定义。

l 优化存储,较少开销(GetValue,SetValue内部使用了一个高效的存储结构),并且依赖属性为静态字段,较少内存分配的空间。

l 处理变更通知、验证、限制,为了提高性能,当属性值改变后,WPF先调用验证,如果验证通过在顺寻执行,如果不通过就不调用后面的操作。

l 可以存储多个值(同一属性拥有多个值)

l 属性值继承(属性值沿着元素树(逻辑树,可视化树)向下传递),对多种提供器支持。

l 属性触发器(eg:鼠标放上、离开按钮的颜色改变)

WP使用其做什么

WPF提供了强大的属性系统,可以支持数据绑定、样式、动画、附加属性等功能

八、 样式

l 样式是一系列对象属性的集合。在类型的不同实例之间共享资源、属性、事件的处理程序,可以看做一组属性值应用到多个元素的捷径。对属性的批处理。

l 代码重用,比资源更好的可重用性和扩展性。

l 把一些控件的通用属性抽离成样式,是这些控件保持一样的风格。并且可以通过样式轻松的改变控件的样式。

l 把UI对象的结构,样式和行为分离这是一种很好的设计

l Style元素属性、资源、事件

实例:Style中定义了资源SolidColorBrush,定义了属性Height和Width,以及使用了EventSetter来定义了Loaded事件的处理。

<Window>

<Window.Resources>

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

<Style.Resources>

<SolidColorBrush x:Key="brush" Color="Yellow"/>

</Style.Resources>

<Setter Property="Height" Value="22"/>

<Setter Property="Width" Value="60"/>

<EventSetter Event="Loaded" Handler="Button_Loaded"/>

</Style>

</Window.Resources>

<x:Code>

<![CDATA[

void Button_Loaded(object sender, RoutedEventArgs e)

{

MessageBox.Show((sender as Button).Name + " Loaded");

}

]]>

</x:Code>

<Grid>

<Button x:Name="button1" Style="{StaticResource ButtonStyle}" Background="{DynamicResource brush}"/>

<Button x:Name="button2" Style="{StaticResource ButtonStyle}" Background="{DynamicResource brush}" Margin="156,144,286,145" />

</Grid>

</Window>

九、 模板

l 模板用来定义或重定义控件外观的。WPF的任何控件都有视觉树和逻辑树。但是Style有它自己的局限性:它只能修改控件已有树型结构的属性,不能修改控件的树型层次结构本身。就想一台电脑使用Style可以改变硬盘、内存等,但不能改变电脑本身。使用模板可以,把电脑变成小汽车。

l 包括三大模板 ControlTemplate、ItemsPanelTemplate(指定用于项的布局的面板)为控件模板,DataTemplate为数据模板,他们都是派生自FramworkTemplate抽象类。

十、 触发器

某个属性值更改时,或某个事件引发时,触发器会相应地设置属性或启动操作(如动画操作)。Style、 ControlTemplate 和 DataTemplate 都具有 Triggers 属性,该属性可以包含一组触发器。 有各种类型的触发器。

种类

l 单一条件触发器

1. 属性触发器(Property Trigger

属性触发器是在当某个依赖属性的值发生变化时触发执行一个Setter的集合,当属性失去这个值时,这些被触发执行的Setter集合会自动被撤销。

Eg: <Style TargetType="Button">

<Setter Property="Height" Value="22"/>

<Setter Property="Width" Value="150"/>

<Style.Triggers>

<Trigger Property="IsMouseOver" Value="true">

<Setter Property="Cursor" Value="Hand" />

</Trigger>

</Style.Triggers>[l1]

</Style>

2. 事件触发器(EventTrigger

根据事件改变触发或启动一组操作。它和PropertyTrigger相似,但是,它的内部不是简单的Setter集合,而是TriggerAction是实例。

Eg:一个圆颜色渐变。

<Ellipse Width="200" Height="200" Name="myEllipse">

<Ellipse.Fill>

<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">

<LinearGradientBrush.GradientStops>

<GradientStop Color="Red" Offset="0" x:Name="SColor" />

<GradientStop Color="Green" Offset="1" x:Name="EColor" />

</LinearGradientBrush.GradientStops>

</LinearGradientBrush>

</Ellipse.Fill>

<Ellipse.Triggers>

<EventTrigger RoutedEvent="Ellipse.Loaded">[l2]

<EventTrigger.Actions>[l3]

<BeginStoryboard>

<Storyboard>

<ColorAnimation From="Red" To="Green" Duration="0:0:4"

AutoReverse="True" RepeatBehavior="Forever"

Storyboard.TargetProperty="Color"

Storyboard.TargetName="SColor"/>

<ColorAnimation From="Green" To="Black" Duration="0:0:4"

AutoReverse="True" RepeatBehavior="Forever"

Storyboard.TargetProperty="Color"

Storyboard.TargetName="EColor" />[l4]

</Storyboard>

</BeginStoryboard>

</EventTrigger.Actions>

</EventTrigger>

</Ellipse.Triggers>

</Ellipse>

3. 数据触发器(DataTrigger)

数据触发器和属性触发器除了面对的对象类型不一样外完全相同。数据触发器是来检测非依赖属性------也就是用户自定义的.NET属性-----的值发生变化时来触发并调用符合条件的一系列Setter集合。

Eg:datagrid控件的某一行的值为某一值时,行颜色改变。

<Style TargetType="DataGridCell">

<Style.Triggers>

<DataTrigger Binding="{Binding Path=S_STUFFNAME[l5] }" Value="李四">

<Setter Property="Background" Value="Red"></Setter>

</DataTrigger>

</Style.Triggers>

</Style>

l 多条件触发器

上面讨论的都是针对单个条件的触发器,也就是说当某一个条件满足时就会触发。而现实中我们可能需要满足很多个条件时才触发一系列操作,这个时候就需要用到MultiDataTrigger或MultiTrigger。MutliDataTrigger和MultiTrigger都具有一个Conditions集合用来存放一些触发条件,这里的Condition之间是and的关系,当所有条件都满足时,Setter集合才会被调用。根据名字就可以看清楚:MultiDataTrigger用来实现多个数据触发器(只用于普通.NET属性)满足条件时调用;MultiTrigger用来实现多个属性触发器(用于依赖属性)满足条件时调用。

Eg:多条件触发器

<MultiTrigger>

<MultiTrigger.Conditions>

<Condition Property="Visibility " Value="Visible" />

<Condition Property="IsEnabled" Value="true" />[l6]

</MultiTrigger.Conditions>

<Setter Property="BorderBrush" Value="Red"/>

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

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

<Setter Property="Foreground" Value="Red" />[l7]

</MultiTrigger>

[l1]触发器

[l2]事件触发器

[l3]事件触发器的TriggerAction集合

[l4]两个目标值之间的 Color 属性值进行动画处理。

[l5]自定义实体属性,当属性值为李四时,行Background颜色为红色

[l6]触发条件

[l7]触发结果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐