第5章 交互和事件处理
Silverlight交互
声明式语言表示XAML提供了很多可能,包括创建所有类型的形状(见第4章),动画元素(见第6章),播放声音视频数据(见第7章)。但如果您在Silverlight中加入少量JavaScript代码,将会释放出它的真实的力量。JavaScript本身是一个强大的语言,但开发者也可以在Silverlight中使用JavaScript API。本书第三部分,特别是第8章,将更详细地讲述JavaScript访问。虽然本书主要关注的是声明式语言XAML,但没有脚本,很多事将不能做。
这一章解释Silverlight事件处理。特别是什么是事件,怎么获取和处理它们。大部份的事件处理代码都以“XAML code-behind”的方式存在于Filename.xaml.js文件中。从技术手段上来说,javaScript代码可以放置在任何JavaScript文件中,只需要在主HTML文件中通过<script>标签来引用就行了。如果在.xaml.js文件中使用触发XAML的JavaScript代码,而在html.js文件中加入触发JavaScript代码的HTML页面,就可以使应用程序更易于打包和开发。
大部份的文件清单最少有三个文件---HTML文件,XAML文件,一个或多个JavaScript文件。部分文件的内容总是很相似,例如createSilverlight()方法的代码。从下一个例子开始,我们将调整内含的XAML文件的,将不再给出createSilverlight()方法的代码。就好象之前没有给出HTML文件的代码一样。尽管如此,您也可以在本书配套的代码(http://www.oreilly.com/catalog/9780596516116)中找到例子的完整代码。
提示:如果对HTML,XAML和JavaScript文件的作用有任何疑问,请复习第2章的基本概念。
事件和事件处理
Silverlight事件是当Silverlight应用程序运行时会发生某些事情。这些事情可能是鼠标单击,鼠标移动,键盘输入,应用程序接受或失去焦点,应用程序开始完全载入或是其他类似的事情。所有事件依赖于一个对象,这样不管鼠标指针在矩形之上还是文本之上,单击时都会有所不同。
Silverlight现在支持超过24个事件,将来的版本可能会更多。本章只关心最重要的一些事件,并提供之前不曾提及到的事件的相关背景知识。
事件处理是一个代码块,在事件发生(或叫触发)时被执行。这里所说的事件和事件处理和HTML中的JavaScript事件概念非常接近。
声明事件处理
有两种途径给一个事件分配一个事件处理---使用声明式方法或使用代码。让我们从第一个选项开始,并使用鼠标事件。Silverlight支持几种鼠标事件,其中之一是用户单击鼠标左键时发生的MouseLeftButtonDown(在鼠标被释放前发生)。
让我们回顾一下第二章的第一个例子“Hello World”,它包含了三个元素,外层的<Canvas>,一个<Rectangle>和一个<TextBlock>。我们给这三个元素添加事件处理。添加一个事件处理非常容易:添加一个和事件名称相同的属性(在此例中,使用LeftMouseButtonDown而不是JavaScript中的OnLeftMouseButtonDown)。这个属性的值是JavaScript的方法名称。当事件触发时将调用这个方法一次。例5-1显示了这个包括三个事件处理的XAML文件:
例5-1 使用事件处理,XAML文件(MouseClick.xaml)
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MouseLeftButtonDown="mouseClick">
<Rectangle Width="200" Height="75" Stroke="Orange" StrokeThickness="15"
MouseLeftButtonDown="mouseClick" />
<TextBlock FontFamily="Arial" FontSize="32" Canvas.Left="30" Canvas.Top="20"
Foreground="Black" Text="Silverlight"
MouseLeftButtonDown="mouseClick" />
Canvas>
JavaScript事件处理方法存在于MouseClick.js.xaml文件内,它象ASP.NET事件处理方法一样接收两个参数:
sender
接收到事件的那个对象的引用,并会调用事件处理。
eventArgs
事件的信息,例如,当处理一个鼠标事件时,可以得到当前鼠标的位置。简单的事件处理方法所做的是显示哪个元素触发了事件。为了实现这个功能,需要使用到sender参数的字符串表达。例如,当<TextBlock>元素触发了事件,sender.toString()所返回的是TextBlock。例5-2中的.xaml.js文件中的“XAML code-behind”代码演示了这项功能。
例5-2 使用事件处理,XAML JavaScript文件(MouseClick.xaml.js)
function mouseClick(sender, eventArgs)
{
alert('Ouch, says ' + sender.toString() + 'l');
}
现在,当您单击文本块时,将会弹出两个JavaScript窗口:一个是文本块的,另一个是canvas的(图5-1)。这叫做“事件浮升机制”。无论何时,当一个元素接收到一个事件,它会把事件向上传播到父节点(在本例中,<TextBlock>把事件传播给<Canvas>)。如果父节点本身还有父节点,事件还会继续向上传播。这种机制和JavaScript在Explorer浏览器里的事件机制很相似,它经常用于嵌套的XAML结构,并且需要为几个对象添加事件处理。当然例5-1的这种机制是很少使用的,一般只给一个元素添加事件处理。
译者注:由于使用了XAML的代码隐藏文件,所以这个例子需要的是四个文件,除了前面一章所讲的三个文件外,还多了一个xaml.js文件。例5-2所演示的就是这个文件。这样就需要在html文件内多加一行代码引用这个文件。在html文件中的
代码后面添加一行
这样就可以正常运行程序了。后面的例子也是这样处理。
当您想改变触发事件的对象时,把Sender属性赋给事件处理方法非常方便。 一般的规则是把每个属性(例如对象的Foreground)暴露给JavaScript。实际上,当JavaScript试图访问属性时,Silverlight会从中截取这些请求并进行转换,使得Silverlight属性可以正确地被获取。这些请求不是大小写敏感的,您可以使用Foreground或foreground。本书使用驼峰命名法:Foreground变为foreground,FontSize变为fontSize。下面再介绍两个鼠标事件:MouseHover(当鼠标指针移动至元素的显示区域之上)和MouseLeave(当鼠标指针离开元素显示区域时)。例5-3创建了一个XAML文件,它使用了这两种事件,并指定了前景色。
例5-3 改变事件目录属性,XAML文件(MouseHover.xaml)
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Rectangle Width="200" Height="75" Stroke="Orange" StrokeThickness="15" />
<TextBlock FontFamily="Arial" FontSize="32" Text="Silverlight"
Canvas.Left="30" Canvas.Top="20"
Foreground="LightGray" MouseEnter="high" MouseLeave="low" />
Canvas>
XAML的代码隐藏的JavaScript文件(例5-4)访问sender参数并设置foreguound属性。结果显示为文本首先显示为亮灰色,但当鼠标移动到它上面时,它会变为黑色。当鼠标离开文本显示区域时,它又变回为亮灰色。图5-2显示了文本的两种状态。
例5-4 改变事件目标属性,XAML JavaScript文件(MouseHover.xaml.js)
function high(sender, eventArgs) {
sender.Foreground = 'Black';
}
function low(sender, eventArgs) {
sender.Foreground = 'LightGray';
}
事件侦听
第二种是使用代码的方法:使用事件侦听把一个事件处理赋给一个事件。您可以安排一段代码“侦听”是否有事件发生。如果发生了,将会进行适当地处理。声明事件处理的主要优势是很容易移除一个事件侦听。不利条件是事件侦听并非自动生成的,特别对于一些有很强的HTML背景的开发人员。但当您第一次使用它,并在程序中使用它根本不困难。
让我们开始一段XAML代码。正如您所见,并没有专门针对单击事件的事件处理属性。好,这有另外一个重要的事件:Loaded。一个元素只会触发一次Loaded事件,如例5-5,整个XAML文件被完全载入后,我们使用这个事件建立实际的事件侦听。
例5-5 使用事件侦听,XAML文件(MouseClickListener.xaml)
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="canvasLoaded">
<Rectangle Width="200" Height="75" Stroke="Orange" StrokeThickness="15" />
<TextBlock FontFamily="Arial" FontSize="32" Canvas.Left="30" Canvas.Top="20"
Foreground="Black" Text="Silverlight"
x:Name="ClickTarget"/>
Canvas>
建立事件侦听
时间证明一切,我们来看看下面这段建立事件侦听的JavaScript代码:
window.onload = function() {
// 这里建立事件侦听
}
当HTML页面标记过完全载入时,页面的Load事件将会被触发一次。当然这并不代表所有相关文件包括JavaScript类库和XAML文件已经被完全载入。当在您的本地计算机上测试它时,它可能不会被执行,因为文件是从速度很快的硬盘上载入的。然而Internet可能会有严重的延迟,所以您不能依赖于这种方法。这也是为什么使用根元素的Loaded事件来初始化Silverlight应用程序并不常用的原因之一。
但现在对于事件侦听来说,首先你不得不寻找跟事件侦听关联的元素。在例5-5中我们应该注意到,元素有一个名称属性(准确地说是x:Name,)。Silverlight的JavaScript API可以通过名称找到相应的元素,实现这个功能您只需要使用findName()方法,它支持XAML文件中的每个元素。
我们可以访问XAML中的元素。需要记住,事件处理方法自动接收一个sender的引用做为他们的第一个参数。所以我们可以使用sender和它的findName()方法来访问文本块:
function canvasLoaded(sender, eventArgs) {
var textblock = sender.findName('ClickTarget');
}
一旦获得了文本块(或其他元素),就可以把事件处理赋给它。完成这个任务的方法是addEventListener(),它有两个参数:
1. 事件的名称
2. 事件处理,也可以是一个方法的引用,或一个匿名方法
textblock.addEventListener('MouseLeftButtonDown',mouseClick);
以上所执行的是实际的事件处理,它输出两个元素,触发的事件和它的名称。例5-6显示了JavaScript文件的完整代码,图5-3是浏览器中的输出效果。
例5-6 使用事件侦听,XAML JavaScript文件(MouseClickListener.xaml.js)
function canvasLoaded(sender, eventArgs) {
var textblock = sender.findName('ClickTarget');
textblock.addEventListener(
'MouseLeftButtonDown',
mouseClick);
}
function mouseClick(sender, eventArgs) {
alert('Ouch, says ' + sender.toString() + '“'+ sender.name + '”!');
}
图5-3 使用程序给事件侦听赋值
移除事件侦听将会使它被“Mouse Position”的代码段所覆盖。
鼠标事件
Silverlight 1.0支持5个鼠标事件,其中三个前面已经介绍过:
MouseEnter
鼠标指针移动到对象显示区域内
MouseLeave
鼠标指针从对象显示区域离开
MouseMove
鼠标移动
MouseLeftButtonDown
鼠标左键按下
MouseLeftButtonUp
鼠标左键单击并释放
这些事件是自解释的,但应该解释一下MouseLeftButtonDown和MouseLeftButtonUp之间的不同之处。单用户在某元素上单击鼠标,首先会触发MouseLeftButtonDown事件,然后是MouseLeftButtonUp事件。所以鼠标单击是在MouseLeftButtonUp事件被触发之后才完成。实际上它们之间只有在一种情况下才会有区别:用户把鼠标指针移动到元素之上,按下鼠标按钮不放,再次移动鼠标离开元素。当您使用MouseLeftButtonUp事件,它将不会被触发,这符合一些场影的需要(如按钮事件),但不符合别一些场影的需要(如鼠标拖动)。
提示:鼠标事件针对矢量图格式SVG的机制如支持三种鼠标事件:按钮按下,按钮释放,按钮单击。
鼠标位置
当您捕获一个鼠标事件,可能想知道鼠标指针当前的位置。关于“在哪里”的问题前面已经回答过,就是对象之上,更具体的问题是“在哪个位置?”。这一点可以转而关注事件处理方法的第二个参数eventArgs。它提供了这些信息,并支持getPosition()方法。
getPosition()方法支持任意的XML元素做为参数。如果设置了它,getPosition()方法将得到鼠标相对于给定元素的坐标。否则,将得到一个绝对坐标(例如,您没有提供参数或参数是一个null值)。
getPosition()方法的返回值是一个带有两个属性x和y的对象,它代表了鼠标指针水平和垂直位置。在Web中,原点表示的是左上角的位置。
例5-7所包含的XAML标记跟踪了鼠标的移动。注意<TextBlock>属性是如何用于显示鼠标指针位置的。另外还需注意主canvas的Loaded事件所执行的方法是canvasLoaded()。
例5-7 显示鼠标位置,XAML文件(MousePosition.xaml)
<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="canvasLoaded">
<Rectangle Width="200" Height="75" Stroke="Orange" StrokeThickness="15" />
<TextBlock FontFamily="Arial" FontSize="28" Canvas.Left="25" Canvas.Top="25"
Foreground="Black"
Text="X: ?? Y: ??" x:Name="MousePosition" />
Canvas>
JavaScript代码的任务是当鼠标移动时确定并输出当前鼠标指针的位置。相关的事件名称是MouseMove,想象中事件侦听的代码应该如下:
function canvasLoaded(sender, eventArgs) {
sender.addEventListener(
'MouseMove',
//事件侦听的引用或代码);
}
现在所需做的事只是写事件侦听,这里我们将使用匿名方法。它使用getPosition()方法确定鼠标位置并写入文本框中。例5-8是完整的JavaScript代码,图5-4可以看到它在浏览器中的效果。
例5-8 显示鼠标位置,XAML JavaScript文件(MousePosition.xaml.js)
function canvasLoaded(sender, eventArgs) {
sender.addEventListener('MouseMove',
function(sender, eventArgs) {
var x = eventArgs.getPosition(null).x;
var y = eventArgs.getPosition(null).y;
sender.findName('MousePosition').text=
'X: '+ x + ' Y: ' + y;
}
);
}
图5-4 显示当前鼠标位置
前面曾经提到过,您可以移除事件侦听。为此您可以在绑定了事件侦听的对象上调用removeEventListener()方法。第一个参数还是事件,但第二个参数可能会让您感到吃惊,它是事件侦听的引用(因为您可以在一个事件上绑定多个事件侦听)。您可以通过在调用addEventListener()方法时保存其返回值来得到这个引用。
为了示范这种机制,我们再次使用鼠标移动,但这一次在单击文本时显示。我们开始于前面的例5-7中的XAML标记,但文件名改为MousePositionToggle.xaml。JavaScript代码也做了很多改变。首先定义两个全局变量。一个用于存放被绑定的事件处理,另一个是一个布尔值,用于用于通知脚本当前是否跟踪鼠标位置。
var
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16396910/viewspace-1030334/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/16396910/viewspace-1030334/