展示
一个鼠标滚动事件的示例
只需要几行
代码即可,我认为大部分人都可以在
几分钟内做好,并理解它是如何工作的。因此我决定将这个事件和Expression Blend中引入的新行为一起合并成
一个例子进行介绍,本文主要介绍
如何创建行为,如何使用鼠标滚动事件,以及如何将其
添加到可滚动的控件上,以
便使用鼠标滚轮。
行为是什么?
你可能曾经在ASP.NET Ajax框架中使用过行为,说得简单点这里的行为就是ASP.NET Ajax语法的Silverlight实现,允许创建可复用的和可连接到HTML控件的行为。(让Silverlight 3操作简单的和手工具)
从Blend 3 Beta版开始引入行为的概念,可以在设计窗口中拖动内置的行为,
增加图形元素的活力,进入Asset
文件夹,
在这里可以找到控件、
效果、资源和其它东西,现在又多了
一个行为卡片。
Expression Blend 3.0 引入了许多行为类型,行为< T>是
其中最简单的了,适用于DependencyOb
ject,行为可以
修改控件的外观,
添加元素,
修改属性或处理
一个或多个事件。MouseDragElementBehavior就是
一个活生生的例子,它连接鼠标事件,让元素可以在
页面中拖动。
编写
一个行为是一件很简单的事情,行为是行为< T>的类扩展,因此首先
要做的是引用C:\Program Files\Microsoft SDKs\Expression\Blend 3\Interactivity\Libraries\Silverlight目录下的Microsoft.Expression.Interaction
s.dll和Sy
stem.Window
s.Interactivity.dll。如果你从Blend 3.0
添加一个现有的行为,那这些动态库会
自动引用到
项目中。
1: public class MouseWheelScrollBehavior : Behavior< Control>
4: }
由于我们是要扩展Silverlight中可滚动的组件,我们需要创建
一个可以连接到Control类的类型,在Silverlight中没有通用的用于可滚动组件(如ScrollViewer、DataGrid和DataGrid)的类,这就需要自己想办法处理才行,我们将在后面进行介绍,目前先分析一下
如何创建一个行为。(微软Silverlight中加入Smooth Streaming)
接下来
要做的是在目标对象上连接MouseWheel事件,当我们完成行为类的扩展后,我们有两个办法来处理连接和释放目标上的行为:将行为连接到对象上时
调用OnAttached,释放对象上的行为时使用OnDetaching。OnAttached和OnDetaching是连接和释放公共事件的理想选择,目标对象是通过行为< T>在AssociatedOb
ject
属性上暴露的,下面是我的
代码示
例:
2: /// Called after the behavior is attached to an AssociatedOb
ject.
4: /// <
REMARKs>Override this to hook up functionality to the AssociatedOb
ject.< /
REMARKs>
5: protected override void OnAttached()
7: thi
s.AssociatedOb
ject.MouseWheel += new MouseWheelEventHandler(AssociatedOb
ject_MouseWheel
);
9: }
10:
12: /// Called when the behavior is being detached from its AssociatedOb
ject,but before it has actually occurred.
14: /// <
REMARKs>Override this to unhook functionality from the AssociatedOb
ject.< /
REMARKs>
15: protected override void OnDetaching()
17: thi
s.AssociatedOb
ject.MouseWheel -= new MouseWheelEventHandler(AssociatedOb
ject_MouseWheel
);
19: }
现在行为已经准备好连接到对象,但它没有做任何事情,我们需要为可滚动组件实现滚动。
滚动可滚动的组件 -- 并非如此简单
由于没有通用的滚动接口,即使为ScrollViewer创建
一个行为比较简单,但为DataGrid或List
Box创建滚动行为却并不简单。
2: /// Gets or sets the peer.
4: /// < value>The peer.< /value>
5: private AutomationPeer Peer
{ get; set; }
6:
8: /// Called after the behavior is attached to an AssociatedOb
ject.
10: /// <
REMARKs>Override this to hook up functionality to the AssociatedOb
ject.< /
REMARKs>
11: protected override void OnAttached()
14:
15: if (thi
s.Peer == null)
16: thi
s.Peer = FrameworkElementAutomationPeer.CreatePeerForElement(thi
s.AssociatedOb
ject
);
17:
18: thi
s.AssociatedOb
ject.MouseWheel += new MouseWheelEventHandler(AssociatedOb
ject_MouseWheel
);
20: }
如果控件已经创建了
自动化接口,我们首先来研究一下它,如果接口不存在,我们需要先创建,AutomationPeer作为
一个成员
属性保存,使用MouseWheel事件时会使用到它,下面是滚动目标对象的示例
代码:
2: /// Handles the MouseWheel event of the AssociatedOb
ject contro
l.
4: /// < param name="sender">The
source of the event.< /param>
5: /// < param name="e">The < see cref="Sy
stem.Window
s.Input.MouseWheelEventArgs"/> instance containing the event data.< /param>
6: void AssociatedOb
ject_MouseWheel(ob
ject sender,MouseWheelEventArgs
E)
8: thi
s.AssociatedOb
ject.Focus(
);
9:
10: int direction = Math.Sign(e.Delta
);
11:
13: (direction < 0) ? Scroll
amount.
smallIncrement : Scroll
amount.
smallDecrement;
14:
15: if (thi
s.Peer
!= null)
17: IScrollProvider scrollProvider =
18: thi
s.Peer.GetPattern(PatternInterface.Scroll) as IScrollProvider;
19:
20: bool shiftKey = (Keyboard.Modifiers & ModifierKey
s.Shift) == ModifierKey
s.Shift;
21:
22: if (scrollProvider
!= null && scrollProvider.VerticallyScrollable && !shiftKey)
24: else if (scrollProvider
!= null && scrollProvider.VerticallyScrollable && shiftKey)
26: }
27: }
我们
获取了Delta后需要
提取出滚动的方向,否则我们就不能指定目标滚动的像素
数量,但Scroll
amount可能是
smallIncrement或
smallDecrement(或LargeIncrement,LargeDecrement),因此使用方向我们
可以确定是递增还是递减。
由于控件既可以
横向滚动也可以纵向滚动,我决定检查换档键是否被按下,如果按下就实现
横向滚动,最后在IScrollProvider中使用Scroll
方法,不需要检查边界。
使用行为
使用Blend应用行为的操作非常简单,Blend资产库会扫描
项目中所有的类,并
显示出来,因此只需要拖动行为到滚动组件上就可以应用行为了,我们需要学习的是通过编码应用行为,下面是
一个例子:
1: < UserControl
4: xmlns:i="clr-namespace:Sy
stem.Window
s.Interactivity;assembly=Sy
stem.Window
s.Interactivity"
5: xmlns:local="clr-namespace:Elite.Silverlight3.MouseWheelSample.Silverlight.Classes"
6: xmlns:data="clr-namespace:Sy
stem.Window
s.Controls;assembly=Sy
stem.Window
s.Control
s.Data"
7: x:Class="Elite.Silverlight3.MouseWheelSample.Silverlight.MainPage"
8: Width="Auto" Height="Auto">
9:
10: ... omissis ...
11:
12: < data:DataGrid Grid.
column="1" Grid.Row="0" Items
source="
{Binding DataItems}" Margin="20">
13: < i:Interaction
.behaviors>
14: < local:MouseWheelScrollBehavior />
15: < /i:Interaction
.behaviors>
16: < /data:DataGrid>
在UserControl中,我们声明了要使用的命名空间,@L_
874_61@个例子中,"i"代表交互,"local"指的是融入了新行为的本地类,在第二部分中我们将行为连接到DataGrid了,将行为连接到ScrollViewer或List
Box的
代码非常类似,运行这个项目,我们在DataGrid上就可以使用鼠标滚轮了。
小结
本文介绍的技术非常有实用价值,几乎适用于所有的可滚动控件,但Combo
Box是个例外,因为它没有直接实现IScrollProvider接口,缺点是只能工作在Windows上,这是
一个较大的问题,
但目前并没有
解决办法,
因为它是目前通过编程实现滚动的唯一
方法,此外我还注意到MouseWheel事件只能在Windows下IE和Firefox (非Windows模式)中工作,这是由Safari和Firefox 的架构决定的,唯一变通的
方法是使用DOM事件。