Navigation导航框架传递参数

最后更新于:2022-04-01 14:21:19

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 上一篇学习了[Silverlight Navigation导航框架URI映射机制](http://www.cnblogs.com/jv9/archive/2011/08/09/2131663.html),其中讨论到Silverlight Navigation导航框架传递参数的问题。说起导航框架页面间传递参数,是最常用开发技巧之一。本篇将详细讲解Silverlight Navigation导航传参方法。 传统Web应用中,由于普通Web页面属于无状态类型页面,所以各页面间传递参数经常使用Cookies,Session或者ViewState技术传递数据。另外,也会经常使用QueryString参数的方式,附加要传递的参数到当前URI链接,共享参数在服务器端和客户端之间。相比而言,Silverlight作为富客户端技术,其应用页面属于有状态类型页面,简单的理解,在Silverlight客户端定义的变量其内容都会被保存在客户端内存中,当前页面状态也将被保存。换句话说,Silverlight页面间传递参数可以定义全局应用级变量进行参数传递,但是这种方式会增加应用内存开支,降低应用运行效率,所以不推荐使用。而Silverlight应用另外一种传递参数的方法与传统Web应用传递参数方法类似,使用 “QueryString参数”的方式实现页面间参数传递。 **“QueryString参数”方式传递参数基础格式** “QueryString参数”方式传递参数,在传统Web应用传参中经常用到,Silverlight仍旧使用传统格式进行URI参数传递操作,其格式如下: /Views/Page.xaml?Parameter=Value 以上链接中,Page.xaml是一个Silverlight客户端应用页面,而需要传递的参数名称为“Parameter”,其参数值为“Value”。通过使用"?"连接页面名称和附带参数,目的页面通过指定API可以获取到附带的参数名称和参数值。 页面间,多参数传递格式如下: /Views/Page.xaml?Parameter1=Value1&Parameter2=Value2 以上链接中使用"&"符号实现在URI中附加多参数,以达到多参数传递目的。 由上面可以看出,“QueryString参数”方式传递参数主要是通过URI,传递方法则与Silverlight导航框架URI地址映射有着密切的联系。 **“QueryString参数”方式传递参数方法** 在上一篇[URI映射机制](http://www.cnblogs.com/jv9/archive/2011/08/09/2131663.html)中,我们曾经介绍过通过在App.xaml资源文件中设置MapperUri,从Home页面传递单一参数到About页面,其映射规则是: <uriMapper:UriMapping Uri="/About/{parameter}" MappedUri="/Views/About.xaml?parameter={parameter}"/> 在源页面,通过NavigationService.Navigate方法对页面进行导航切换,其中附带需要传递的参数, ~~~ privatevoid btSend_Click(object sender, RoutedEventArgs e) { this.NavigationService.Navigate(new Uri(String.Format("/About/"+ txtQueryString.Text.Trim()), UriKind.Relative)); } ~~~ 在Navigation导航框架运行时,在浏览器中URI地址格式为: http://localhost:49750/SilverlightNavigationDemoTestPage.aspx#/About/SilverlightChina 通过URI地址映射解析,其实际地址将指向到"/Views/About.xaml?parameter=SilverlightChina", ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67d09fb39.gif) 根据以上介绍,如果需要传递多参数到目的页面,则需要添加新的地址映射规则,其中附带多个参数即可。例如添加规则: <uriMapper:UriMappingUri="/About/{name}&amp;{url}" MappedUri="/Views/About.xaml?name={name}&amp;url={url}"/> 使用NavigationService.Navigate方法对页面进行导航切换,其中附带需要传递的多个参数: ~~~ privatevoid btSendMultiple_Click(object sender, RoutedEventArgs e) { this.NavigationService.Navigate(new Uri(String.Format("/About/"+ txtNameString.Text.Trim()+"&"+ txtURLString.Text.Trim()), UriKind.Relative)); } ~~~ 在映射规则中,使用{name}和{url} 作为URI通用符,两者使用"&amp"是“&”符号的HTML表示方法。 在Navigation导航框架运行时,在浏览器中URI地址格式为: http://localhost:49750/SilverlightNavigationDemoTestPage.aspx#/About/%E9%93%B6%E5%85%89%E4%B8%AD%E5%9B%BD%E7%BD%91&SilverlightChina.Net 通过URI地址映射解析,其实际地址将指向到"/Views/About.xaml?name=%E9%93%B6%E5%85%89%E4%B8%AD%E5%9B%BD%E7%BD%91&url=SilverlightChina.Net" ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67d0aee2e.gif) **读取“QueryString参数”方式传递参数值** Silverlight Navigation导航框架完成参数传递后,其目的页面,需要使用NavigationContext对象中的QueryString属性读取当前URI中包含的传递参数名称,以获取其参数值。其基本格式如下: object parameter = this.NavigationContext.QueryString["parameter"]; 以上面两个例程而言,其读取参数格式如下: ~~~ protectedoverridevoid OnNavigatedTo(NavigationEventArgs e) { if (this.NavigationContext.QueryString.ContainsKey("parameter")) { tbReceiveParameter.Text ="接收到的传递参数值:"+this.NavigationContext.QueryString["parameter"]; } else { tbReceiveParameter.Text ="接收参数1: "+this.NavigationContext.QueryString["name"]+" 接收参数2:"+this.NavigationContext.QueryString["url"]; } } ~~~ 在使用NavigationContext读取参数时,有以下两点需要注意: - 读取参数前需要检测参数名称是否存在,如果NavigationContext.QueryString中不存在需要获取的参数名称,则应用会出现异常;而参数值允许为空,如果参数值空,则返回Null到页面。常用检测代码如下:NavigationContext.QueryString.ContainsKey(paramName) - 参数赋值前需要进行参数类型转换,因为参数传递是以字符串形式传递,而页面赋值时则需要根据需求进行值类型转换,否则应用会出现异常;常用类型转换代码如下:int.TryParse(NavigationContext.QueryString[paramName], out paramValue) 最后,从MSDN转一个URI地址映射解析匹配对照表,其中包括URI附带参数实例: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67d0bfcb0.gif) 今天讲到这里,如果您有问题,欢迎留言讨论。 [源代码下载](http://www.silverlightchina.net/uploads/soft/110809/1-110P91IU3.rar) [Silverlight实例教程系列 - Silverlight Validation验证实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html) [Silverlight实例教程系列 - Silverlight Out-of-Browser实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0809/1709.html) [Silverlight实例教程系列 - Expression Blend实例中文教程](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0409/978.html) 欢迎大家加入“专注Silverlight”QQ技术群,欢迎大家加入一起学习讨论Silverlight&WPF&Widnows Phone开发技术。 22308706(一群) 超级群500人 37891947(二群) 超级群500人 100844510(三群) 高级群200人 32679922(四群) 超级群500人 23413513(五群) 高级群200人 32679955(六群) 超级群500人 61267622(七群) 超级群500人 88585140(八群) 超级群500人 128043302(九群 企业应用开发推荐群) 高级群200人 101364438(十群) 超级群500人 68435160(十一群 企业应用开发推荐群)超级群500人
';

Navigation导航框架URI映射机制

最后更新于:2022-04-01 14:21:17

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在[上几篇](http://blog.csdn.net/jv9/article/details/6640506)Silverlight Navigation导航框架教程中,主要介绍了Silverlight Navigation导航框架基础,本篇开始将结合实例介绍Silverlight Navigation导航框架的应用。按照个人经验来讲,学习Silverlight Navigation导航框架应用,首先需要了解导航框架对URI地址映射原理,所以,本篇将介绍Navigation导航框架URI映射机制。 **快速理解URI映射机制概念** 对于熟悉ASP.NET MVC路由机制的开发人员来讲,ASP.NET MVC URL路由机制并不陌生。而Silverlight导航框架URI映射机制的概念和ASP.NET MVC URL路由机制相类似,使用指定格式的URI表示原始URI信息,并生成映射关系,在项目运行时,Silverlight导航框架URI映射类将解析预先定义的URI变量,向其对应URI映射发出请求,以达到页面跳转或参数传递的目的。 从原理上讲,向Silverlight导航框架Frame类添加URI映射是定义UriMapper类的一个或者多个UriMapping实例的过程。而UriMapper类主要的功能是根据映射对象集合中指定的匹配对象规则,将统一资源标识符(URI)转换为新的URI,将请求的URI映射到不同的URI中。需要注意的是URI映射是将URI指向一个字符串类型变量,而不是实际的文件路径。 在定义映射规则时,不需要使用完全匹配的URI,可以包含占位符号作为替换标识。 为了方便演示本篇实例,将使用“[Silverlight实例教程 - 理解Navigation导航框架Frame类](http://blog.csdn.net/jv9/article/details/6576016)”文章中的源代码项目作为演示项目。 **Navigation框架URI映射的使用** 在实际项目中,使用Silverlight导航框架URI映射功能前需要在App.xaml资源文件中添加一个UriMapper对象作为XAML资源,在资源文件中,将声明所有需要URI映射的变量。最基本的代码格式如下: ~~~ <Application      x:Class="SilverlightNavigationDemo.App"   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation">   <Application.Resources>            <uriMapper:UriMapper x:Name="PageMapper">         <uriMapper:UriMapping Uri="/Home" MappedUri="/Views/Home.xaml"/>         <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>     </uriMapper:UriMapper>          </Application.Resources> </Application> ~~~ 在UriMapper对象中,添加UriMapping对象,该对象将当前Navigation框架传递的URI进行映射转换,指向项目目录中真实页面路径。  在本实例中,使用<uriMapper:UriMapping Uri="/Home" MappedUri="/Views/Home.xaml"/>定义简单导航框架URI映射规则,其含义是使用URI = “/Home”,匹配解析到 /Views/Home.xaml页面,下图中,URI在地址栏中,仅显示/Home,而实际文件指向则是/Views/Home.xaml。 该映射规则是Navigation导航框架中最简单的页面映射。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67d03a445.gif) **导航框架通用映射符号** 而UriMapper对象除了支持以上标准映射格式外,同时也支持占位符号作为通用映射符号,实现页面映射功能,其中占位符号名称作为变量的形式可以被匹配该段中的任何值替换。 其语法表示方式是:  **{占位字段名}** 例如: <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/> 该映射规则使用{pageName}作为通用映射占位符号,通过Navigation导航框架解析后,将指向/Views/{pageName}.xaml页面。如果将{pageName}替换为Home,该规则将于第一条映射规则相同,如下: <uriMapper:UriMapping Uri="/Home" MappedUri="/Views/Home.xaml"/> 完成地址映射机制设置后,需要对当前项目的Navigation导航框架Frame类UriMapper属性进行赋值,将该属性关联至App.xaml资源文件中的UriMapper类,其赋值方法如下: ~~~ <navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}" UriMapper="{StaticResource PageMapper}" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed"> </navigation:Frame> ~~~ **导航框架映射机制传递参数** 通过Silverlight Navigation导航框架机制,可以实现页面间参数传递功能。例如,在项目Home页面输入一个参数值,传递到About页面中,其映射规则如下: ~~~ <uriMapper:UriMapping Uri="/About/{parameter}" MappedUri="/Views/About.xaml?parameter={parameter}"/> ~~~ 在Navigation导航框架运行时, 解析URI传递参数,指向到"/Views/About.xaml?parameter=Hello%20Silverlight",通过对NavigationContext的调用,About页面即可获得传递的参数值。(对于Silverlight Navigation传参,将在下一篇详细介绍) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67d059faa.gif) **URI映射机制优点** 使用Silverlight导航框架URI映射机制不仅可以提供友好的URI访问格式,同时也可以用于隐藏项目页面名称,从而保护项目内部结构的作用。 需要注意的一点,Silverlight导航框架URI映射机制变量解析具有一定顺序性,URI请求响应顺序是由具体映射路径到通用映射路径。 例如,简单修改以上映射机制规则的顺序如下: ~~~ <uriMapper:UriMapper x:Name="PageMapper">         <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>         <uriMapper:UriMapping Uri="/Home" MappedUri="/Views/Home.xaml"/>         <uriMapper:UriMapping Uri="/About/{parameter}" MappedUri="/Views/About.xaml?parameter={parameter}"/> </uriMapper:UriMapper> ~~~ 在 Silverlight导航框架执行时, 如果试图传递参数到About页面,则会弹出异常信息,提示无法找到/About/Hello Silverlight页面。 这是因为在UriMapper对象中,首先定义{pageName}的映射地址,在发出/About页面请求时,导航框架映射机制将首先匹配 {pageName},如果匹配成功,也就不再继续向下面的规则查询匹配。而<uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>和 <uriMapper:UriMapping Uri="/About/{parameter}" MappedUri="/Views/About.xaml?parameter={parameter}"/>相比较而言,更加具有通用性,所以正确顺序应该是从局部到全局的方向,才能够正确映射URI页面。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67d07f765.gif) Silverlight Navigation框架URI映射机制技巧提示 导航框架Uri映射路径允许设置为空值,设置空值时可以创建一个初始化页面,在第一次运行时映射将指向该初始化页面,同时也可以防止在Uri映射出现空值时返回异常。 例如,修改Home页面URI映射规则如下: <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/> 每次运行项目,Home页面都会作为默认首页载入。 在不使用Uri空值映射时,建议在Frame.NavigationFrailed事件中控制导航框架异常处理。例如,当用户重复使用导航后退功能,直到导航第一个页面时为用户设置提示信息,避免出现异常操作。 Silverlight Navigation导航框架URI映射机制就讲到这里,下一篇,将通过导航框架传参功能,理解URI映射机制的应用。 [本篇源代码](http://www.silverlightchina.net/uploads/soft/110808/1-110PQA407.rar) [Silverlight实例教程系列 - Silverlight Validation验证实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html) [Silverlight实例教程系列 - Silverlight Out-of-Browser实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0809/1709.html) [Silverlight实例教程系列 - Expression Blend实例中文教程](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0409/978.html) 欢迎大家加入“专注Silverlight”QQ技术群,欢迎大家加入一起学习讨论Silverlight&WPF&Widnows Phone开发技术。  22308706(一群) 超级群500人  37891947(二群) 超级群500人  100844510(三群) 高级群200人  32679922(四群) 超级群500人  23413513(五群) 高级群200人  32679955(六群) 超级群500人  61267622(七群) 超级群500人  88585140(八群) 超级群500人  128043302(九群 企业应用开发推荐群) 高级群200人  101364438(十群) 超级群500人  68435160(十一群 企业应用开发推荐群)超级群500人
';

理解Navigation导航框架Page类

最后更新于:2022-04-01 14:21:15

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在“[Silverlight实例教程 - 理解Navigation导航框架Frame类](http://blog.csdn.net/jv9/article/details/6576016)” 介绍了Silverlight Navigation框架主要对象之一,Frame类,该类可以被简单的理解为Silverlight Navigation页面承载框架,框架中提供丰富的属性,方法和事件,从而实现Navigation框架功能。本篇将继续介绍Silverlight Navigation框架另外一个重要对象,Page类。 Page类,在Silverlight导航框架中主要功能是作为导航内容页载入到导航框架Frame类,从功能上来讲Page类是一个Silverlight UserControl, 而不同的是,Page类具备特定的导航属性和方法。 同样,从Asp.Net应用开发角度理解,Page类可以被看作为Master Page承载具体功能的子页面。  从Silverlight SDK中可以看出,Page类继承System.Windows.Controls.UserControl,也就是说Page类是一个用户控件类,可被任何ContentControl内容控件类(Frame类)承载显示。 ~~~ System.Object    System.Windows.DependencyObject      System.Windows.UIElement        System.Windows.FrameworkElement          System.Windows.Controls.Control             System.Windows.Controls.UserControl                 System.Windows.Controls.Page ~~~ 虽然Page类页面派生自UserControl,但是作为独立页面类,其具有特殊的页面命名空间,其页面初始化XAML代码如下: ~~~ <navigation:Page x:Class="SilverlightNavigationDemo.Home"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"     mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"     Title="首页"     Style="{StaticResource PageStyle}"> ~~~ 与UserControl页面不同的是<navigation:Page ..> </navigation:Page> . 值得注意的是,Silverlight导航框架Page类派生自UserControl,没有提供特定的事件,而该类继承了UserControl类事件。 从前文可知,在Silverlight导航框架中,Frame类功能是承载Page类,在整个导航过程中,两个类相互依存,而完整的导航进程事件运行顺序如下图:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67d018ce6.gif) 虽然Silverlight导航框架Page类没有定义专属事件,但是该类提供了专属的属性和方法,以供开发人员在导航过程中,对Page页面进行控制。 Silverlight导航框架常用**Page类属性**: <table style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">属性</span></strong></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">类型</span></strong></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 224.15pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="299"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">描述</span></strong></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationCacheMode</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationCacheMode</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 224.15pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="299"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该属性用于获取或设置一个值,改制指定当前导航页面是否开启导航缓存;该属性默认值为</span><span style="font-family:宋体;FONT-SIZE: 12pt">Disabled</span><span style="font-family:宋体;FONT-SIZE: 12pt">(表示不开启导航缓存),</span><span style="font-family:宋体;FONT-SIZE: 12pt">Enabled</span><span style="font-family:宋体;FONT-SIZE: 12pt">和</span><span style="font-family:宋体;FONT-SIZE: 12pt">Required</span><span style="font-family:宋体;FONT-SIZE: 12pt">属性值表示开启导航缓存,其不同的是</span><span style="font-family:宋体;FONT-SIZE: 12pt">Required</span><span style="font-family:宋体;FONT-SIZE: 12pt">不受</span><span style="font-family:宋体;FONT-SIZE: 12pt">CacheSize</span><span style="font-family:宋体;FONT-SIZE: 12pt">限制,每次导航时都重复利用缓存实例;而</span><span style="font-family:宋体;FONT-SIZE: 12pt">Enabled</span><span style="font-family:宋体;FONT-SIZE: 12pt">受制于</span><span style="font-family:宋体;FONT-SIZE: 12pt">CacheSize</span><span style="font-family:宋体;FONT-SIZE: 12pt">缓存尺寸,超过尺寸时则放弃缓存实例</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationContext</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationContext</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 224.15pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="299"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">获取当前导航请求中的对象信息,该属性常被用于获取</span><span style="font-family:宋体;FONT-SIZE: 12pt">URI</span><span style="font-family:宋体;FONT-SIZE: 12pt">查询字符串值,实现导航框架传值</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationService</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationService</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 224.15pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="299"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">获取当前导航框架导航服务实例,通过该属性可以获取当前页面导航请求,该属性将在后文详细讲解。</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">Title</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 106.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="142"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">String</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 224.15pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="299"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该属性用于获取或设置当前导航页面的名称</span></p></td></tr></tbody></table> Silverlight导航框架常用**Page类方法**: <table style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 130.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="174"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">方法</span></strong></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 312pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="416"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">描述</span></strong></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 130.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="174"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">OnFragmentNavigation</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 312pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="416"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法在导航到页面上的片段时被调用</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 130.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="174"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">OnNavigatedFrom</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 312pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="416"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法在当前页面不再为导航框架中的活动页面时被调用</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 130.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="174"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">OnNavigatedTo</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 312pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="416"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法在当前页面成为导航框架中的活动页面时被调用</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 130.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="174"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">OnNavigatingFrom</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 312pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="416"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法在当前页面不再为导航框架中的活动页面前被调用</span></p></td></tr></tbody></table> **Page类的NavigationService属性** 在 Page类属性中,最常用的属性是NavigationService, 该属性主要提供页面导航入口点地址,简单的理解是该属性是为导航框架Page类页面提供框架内页面内部导航功能,从某一页面内导航到其他 页面或者当前页面的其他表示形式。NavigationService属性提供 一个同名对象类NavigationService,所以,学习NavigationService属性也就是学习NavigationService类的过程。 **NavigationService类**包含五个方法帮助实现页面内导航功能, <table style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">方法</span></strong></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">描述</span></strong></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">GoBack</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于导航当前页面后退到历史记录中上一页,如果后退导航时没有历史记录页面,则返回异常</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">GoForward</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于导航当前页面前进到历史记录中下一页,如果前进导航时没有历史记录页面,则返回异常</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">Navigate</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于导航到指定</span><span style="font-family:宋体;FONT-SIZE: 12pt">URI</span><span style="font-family:宋体;FONT-SIZE: 12pt">页面,该</span><span style="font-family:宋体;FONT-SIZE: 12pt">URI</span><span style="font-family:宋体;FONT-SIZE: 12pt">可以是导航映射相对地址,也可以是导航页面绝对地址</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">Refresh</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于重载当前导航页,该方法经常被用于自定义</span><span style="font-family:宋体;FONT-SIZE: 12pt">INavigationContentLoader</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">StopLoading</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于停止所有导航异步进程,该方法常被用于停止正在下载载入的导航页面</span></p></td></tr></tbody></table> 另外,NavigationService类提供以下常用属性和事件: <table style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">方法</span></strong></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">描述</span></strong></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">GoBack</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于导航当前页面后退到历史记录中上一页,如果后退导航时没有历史记录页面,则返回异常</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">GoForward</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于导航当前页面前进到历史记录中下一页,如果前进导航时没有历史记录页面,则返回异常</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">Navigate</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于导航到指定</span><span style="font-family:宋体;FONT-SIZE: 12pt">URI</span><span style="font-family:宋体;FONT-SIZE: 12pt">页面,该</span><span style="font-family:宋体;FONT-SIZE: 12pt">URI</span><span style="font-family:宋体;FONT-SIZE: 12pt">可以是导航映射相对地址,也可以是导航页面绝对地址</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">Refresh</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于重载当前导航页,该方法经常被用于自定义</span><span style="font-family:宋体;FONT-SIZE: 12pt">INavigationContentLoader</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 104.65pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="140"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">StopLoading</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 333.1pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="444"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该方法用于停止所有导航异步进程,该方法常被用于停止正在下载载入的导航页面</span></p></td></tr></tbody></table> <table style="BORDER-BOTTOM: medium none; BORDER-LEFT: medium none; BORDER-COLLAPSE: collapse; BORDER-TOP: medium none; BORDER-RIGHT: medium none" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 118.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="158"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">事件</span></strong></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 324pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="432"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><strong><span style="font-family:宋体;FONT-SIZE: 12pt">描述</span></strong></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 118.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="158"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">FragmentNavigation</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 324pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="432"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该事件在导航到内容片段时被激活</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 118.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="158"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">Navigated</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 324pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="432"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该事件在导航完成时被激活</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 118.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="158"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">Navigating</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 324pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="432"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该事件在导航开始时被激活</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 118.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="158"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationFailed</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 324pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="432"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该事件在导航抛出异常失败时被激活</span></p></td></tr><tr><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: windowtext 1pt solid; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 118.8pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="158"><p style="TEXT-ALIGN: center; LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt" align="center"><span style="font-family:宋体;FONT-SIZE: 12pt">NavigationStopped</span></p></td><td style="BORDER-BOTTOM: windowtext 1pt solid; BORDER-LEFT: medium none; PADDING-BOTTOM: 0cm; PADDING-LEFT: 5.4pt; WIDTH: 324pt; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; BORDER-RIGHT: windowtext 1pt solid; PADDING-TOP: 0cm" width="432"><p style="LINE-HEIGHT: normal; MARGIN-BOTTOM: 0pt"><span style="font-family:宋体;FONT-SIZE: 12pt">该事件在</span><span style="font-family:宋体;FONT-SIZE: 12pt">StopLoading</span><span style="font-family:宋体;FONT-SIZE: 12pt">方法被调用时,或者取消当前导航请求时被激活</span></p></td></tr></tbody></table> 而与上一篇介绍Frame类对比,会发现NavigationService类提供的属性,方法和事件和Frame类中的属性,方法和事件基本类似,其功能性也有重叠。从而可以这样理解,在Silverlight导航框架Page类中,允许在导航页面内触发页面导航行为,其效果与Frame类实现效果相同。 例如: this.NavigationService.Navigate(new Uri(“/Home.xaml”, UriKind.Relative)); 但是,两者也有不同之处,例如Frame类提供部分依赖属性,可供控件进行直接绑定和调用,例如IsEnabled, 通过该属性可以实现当前Frame是否可用。而NavigationService不能实现该绑定效果。 对于NavigationService类而言,其页面导航方法如上代码,值得注意的是该类包含两个特殊的方法,分别是Refresh()和StopLoading(), 这两个方法主要针对当前页面进行操作,其简单描述如下: **Refresh方法**,功能类似浏览器的刷新按钮,该方法将重载当前Page类页面,实现页面刷新效果,如果页面允许支持缓存,将从缓存中读取当前页面。 **StopLoading方法**,功能类似浏览器的停止按钮,该方法将停止正在运行的页面载入进程或者其他异步进程,在实际项目中,该方法并不常用。 **Page类的NavigationContext属性** Page 类提供的另外一个重要属性是NavigationContext属性,该属性提供一个NavigationContext对象,而该对象中包含两个常用属性分别是Uri和QueryString。在实际项目中,经常会使用NavigationContext.Uri获取当前URI路径字符串,使用 NavigationContext.QueryString获取导航页面传值。 例如: string uriText = String.Format(“/User.xaml?userID={0}&role={1}”, userID, userRole); mainFrame.Navigate(new Uri(uriText), UriKind.Relative); 执行以上代码,当前导航框架将访问如下地址: /User.xaml?userID=6&role=1 在User.xaml页面将使用NavigationContext.QueryString获取userID和userRole参数值,以获取详细用户信息。 ~~~ int userID, userRole; if (this.NavigationContext.QueryString.ContainsKey(“userID”))       userID = Int32.Parse(this.NavigationContext.QueryString[“userID”]); if (this.NavigationContext.QueryString.ContainsKey(“userRole”))       userRole = Int32.Parse(this.NavigationContext.QueryString[“userRole”]); ~~~ **Page类的NavigationCacheMode属性** Page 类的NavigationCacheMode属性是Silverlight导航框架重要属性之一,其功能可以保存导航页面状态。 NavigationCacheMode属性中包含有三个枚举成员,分别是Disabled,Required和Enabled,其含义分别是: NavigationCacheMode.Disabled: 不支持缓存页面,每次导航应用访问时创建 一个新的页面实例; NavigationCacheMode.Required: 支持缓存页面,并且每次导航应用访问时都重复利用该缓存实例,而且忽略Frame类中CacheSize属性设置大小; NavigationCacheMode.Enabled: 支持缓存页面,如果超过Frame类中CacheSize属性设置尺寸,则放弃保存缓存实例; 默认情况下,NavigationCacheMode为Disabled状态,也就是说,在Silverlight导航框架应用时,不记录任何信息到缓存。当NavigationCacheMode状态设置为Required后,每当用户结束一次导航操作,Frame类将保存页面对象到内存,当用户点击返回或者前进时,将重新载入保存的缓存状态到当前Page类页面,而当前Page类页面的构造函数不再执行,但是其Loaded事件将被激活。当 NavigationCacheMode为Enabled状态时,则会参考Frame类中CacheSize属性设置尺寸设置。例如:如果设置Frame 类CacheSize属性值为6,当第七个Page类页面载入时,第一个载入到缓存的Page类 页面将会从缓存中删除,而最新的Page类页面将会替代。 需要注意的是,当允许导航页面缓存时,位于内存中的导航页面具有完整的页面处理流程,也就是说,当前台页面重新刷新载入时,缓存中所有的页面Loaded事件都会同时执行,从而达到保存页面状态的目的,当用户需要访问上一级或下一级页面时,则会节省页面初始化事件,相对提高应用效率。 Silverlight导航框架Page类属于导航基础类之一,在随后的实例演示中,会经常用到其属性和方法,对于该类推荐认真学习。 今天暂时介绍到这里。下一篇将介绍Silverlight导航框架常用应用话题。 [Silverlight实例教程系列 - Silverlight Validation验证实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html) [Silverlight实例教程系列 - Silverlight Out-of-Browser实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0809/1709.html) [Silverlight实例教程系列 - Expression Blend实例中文教程](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0409/978.html) 欢迎大家加入“专注Silverlight”QQ技术群,欢迎大家加入一起学习讨论Silverlight&WPF&Widnows Phone开发技术。  22308706(一群) 超级群500人  37891947(二群) 超级群500人  100844510(三群) 高级群200人  32679922(四群) 超级群500人  23413513(五群) 高级群200人  32679955(六群) 超级群500人  61267622(七群) 超级群500人  88585140(八群) 超级群500人  128043302(九群 企业应用开发推荐群) 高级群200人  101364438(十群) 超级群500人  68435160(十一群 企业应用开发推荐群)超级群500人
';

理解Navigation导航框架Frame类

最后更新于:2022-04-01 14:21:12

通过“[Navigation导航框架开篇](http://www.cnblogs.com/jv9/archive/2011/05/18/2049518.html)” 的介绍,可以了解到Silverlight导航框架可被应用于多种场合,最为常见的是实现Silverlight项目内部页面切换。在 Silverlight SDK中,导航框架API位于System.Windows.Navigation命名空间,为了更好的掌握Silverlight导航框架,本篇将介绍 Silverlight导航框架结构以及常用类和方法使用说明。 **快速创建简单Silverlight导航应用** 在开始讲解理论知识前,首先创建一个基于Silverlight导航框架的简单应用,其步骤如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cf6f83b.png) 创建Silverlight Navigation Application,项目名称”SilverlightNavigationDemo“ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cf859a3.png) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cf96220.png) 创建完成后,Visual Studio 2010将自动生成项目文件以及默认项目页面。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cfa7273.png) 直接编译运行默认生成的Silverlight导航应用项目,默认运行界面如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cfb588e.png) 在默认项目中,系统自动生成导航菜单”home“和”about“,点击后,在导航框架内将自动切换页面。 为了演示方便,我将默认导航应用中的英文介绍修改为中文。 **理解Silverlight导航框架Frame类** Silverlight导航框架包含两个主要对象,分别是Frame类和Page类。 **Frame类** 主要功能是承载显示项目页面,从功能上来讲类似一个内容控件,Frame类可以承载任何继承自UserControl类的控件或者页面作为导航的目标页。从 ASP.NET应用开发角度理解,Frame类可以被看作为Master Page中的ContentPlaceHolder,可被用于载入任何不同的页面。****Frame类执行的原理是,当用户执行导航指令时,会传递指定的URI到一个类型转换器中获取导航页面路径,然后在Frame控件中显示该页面。 从Silverlight SDK中可以看出,Frame类继承System.Windows.Controls.ContentControl,也就是说Frame类是一个ContentControl内容控件类,该类同一时间仅能包含一个内容项。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cfc57d9.png)   在文章开始的默认实例中,MainPage.xaml代码中包含一个<navigation:Frame>对象,其中使用Source属性指定Frame对象运行时所指向的Uri,使用Frame.UriMapper地址映射,载入真实页面地址。对于导航框架的地址映射将在后文介绍。 ~~~ <navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"                                Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">                 <navigation:Frame.UriMapper>                   <uriMapper:UriMapper>                     <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>                     <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>                   </uriMapper:UriMapper>                 </navigation:Frame.UriMapper> </navigation:Frame> ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cfd3d56.png) Frame 类作为导航页面载体,通过设置JournalOwnership属性记录项目页面导航历史,同时通过GoBack和GoForward可以轻松实现导航页面的后退和前进。另外Frame类中提供UriMapper属性,实现导航页面地址映射功能,该功能不仅简化页面Uri,方便记忆,同时也相对提高了页面安全性。 Silverlight导航框架Frame类常用**属性**: <table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; padding-top: 0cm; border: windowtext 1pt solid;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><strong><span style="font-family: 宋体; font-size: 12pt;">属性</span></strong></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><strong><span style="font-family: 宋体; font-size: 12pt;">类型</span></strong></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><strong><span style="font-family: 宋体; font-size: 12pt;">描述</span></strong></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; color: red; font-size: 12pt;">CacheSize</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Int</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于获取或设置导航框架缓存页面数量</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">CanGoBack</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Bool</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于判断后退导航历史记录中是否至少有一条记录</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">CanGoForward</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Bool</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于判断前进导航历史记录中是否只要有一条记录</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">ContentLoader</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">ContentLoader</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于获取或设置一个负责提供请求</span><span style="font-family: 宋体; font-size: 12pt;">URI</span><span style="font-family: 宋体; font-size: 12pt;">对应的内容对象</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">CurrentSource</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Uri</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于获取当前框架中内容页的统一资源标识符(</span><span style="font-family: 宋体; font-size: 12pt;">URI</span><span style="font-family: 宋体; font-size: 12pt;">)</span><span style="font-family: 宋体; font-size: 12pt;">,</span><span style="font-family: 宋体; font-size: 12pt;">该属性值仅在导航完成后进行更新。</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; color: red; font-size: 12pt;">JournalOwnership</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">JournalOwnership</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于获取或设置当前</span><span style="font-family: 宋体; font-size: 12pt;">Frame</span><span style="font-family: 宋体; font-size: 12pt;">框架是否记录导航历史记录,或者是否将浏览记录与浏览器集成</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; color: red; font-size: 12pt;">Source</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Uri</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于获取或设置当前框架中内容页的统一资源标识符(</span><span style="font-family: 宋体; font-size: 12pt;">URI</span><span style="font-family: 宋体; font-size: 12pt;">),与</span><span style="font-family: 宋体; font-size: 12pt;">CurrentSource</span><span style="font-family: 宋体; font-size: 12pt;">属性不同的是该属性值在导航开始时即被设置,当导航完成时,该属性值和</span><span style="font-family: 宋体; font-size: 12pt;">CurrentSource</span><span style="font-family: 宋体; font-size: 12pt;">相同。</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; color: red; font-size: 12pt;">UriMapper</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 106.8pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="142"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">UriMapperBase</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 224.15pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="299"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该属性用于获取或设置一个导航映射对象,该对象用于管理导航框架地址转换</span></p></td></tr></tbody></table> Silverlight导航框架Frame类常用**方法**: <table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; padding-top: 0cm; border: windowtext 1pt solid;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><strong><span style="font-family: 宋体; font-size: 12pt;">方法</span></strong></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><strong><span style="font-family: 宋体; font-size: 12pt;">描述</span></strong></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; color: red; font-size: 12pt;">GoBack</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该方法用于导航当前页面后退到历史记录中上一页,如果后退导航时没有历史记录页面,则返回异常</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; color: red; font-size: 12pt;">GoForward</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该方法用于导航当前页面前进到历史记录中下一页,如果前进导航时没有历史记录页面,则返回异常</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; color: red; font-size: 12pt;">Navigate</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该方法用于导航到指定</span><span style="font-family: 宋体; font-size: 12pt;">URI</span><span style="font-family: 宋体; font-size: 12pt;">页面,该</span><span style="font-family: 宋体; font-size: 12pt;">URI</span><span style="font-family: 宋体; font-size: 12pt;">可以是导航映射相对地址,也可以是导航页面绝对地址</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Refresh</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该方法用于重载当前导航页,该方法经常被用于自定义</span><span style="font-family: 宋体; font-size: 12pt;">INavigationContentLoader</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">StopLoading</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该方法用于停止所有导航异步进程,该方法常被用于停止正在下载载入的导航页面</span></p></td></tr></tbody></table> Silverlight导航框架Frame类常用**事件:** <table style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td style="padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; padding-top: 0cm; border: windowtext 1pt solid;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><strong><span style="font-family: 宋体; font-size: 12pt;">事件</span></strong></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><strong><span style="font-family: 宋体; font-size: 12pt;">描述</span></strong></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">FragmentNavigation</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该事件在导航到内容片段时被激活</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Navigated</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该事件在导航完成时被激活</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">Navigating</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该事件在导航开始时被激活</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">NavigationFailed</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该事件在导航抛出异常失败时被激活</span></p></td></tr><tr><td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; width: 104.65pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="140"><p style="text-align: center; line-height: normal; margin-bottom: 0pt;" align="center"><span style="font-family: 宋体; font-size: 12pt;">NavigationStopped</span></p></td><td style="border-bottom: windowtext 1pt solid; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 333.1pt; padding-right: 5.4pt; border-top: medium none; border-right: windowtext 1pt solid; padding-top: 0cm;" width="444"><p style="line-height: normal; margin-bottom: 0pt;"><span style="font-family: 宋体; font-size: 12pt;">该事件在</span><span style="font-family: 宋体; font-size: 12pt;">StopLoading</span><span style="font-family: 宋体; font-size: 12pt;">方法被调用时,或者取消当前导航请求时被激活</span></p></td></tr></tbody></table> Silverlight导航框架Frame类事件运行周期图如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cfec75a.png) Silverlight导航框架Frame类属于导航应用基础,在随后的实例演示中,会经常用到其属性和方法,对于该类推荐认真学习。 今天暂时介绍到这里。下一篇将介绍Silverlight导航框架Page类以及其主要属性和方法的使用。 [本篇源代码](http://www.silverlightchina.net/uploads/soft/110628/1-11062Q63134.zip) [Silverlight实例教程系列 - Silverlight Validation验证实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html) [Silverlight实例教程系列 - Silverlight Out-of-Browser实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0809/1709.html) [Silverlight实例教程系列 - Expression Blend实例中文教程](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0409/978.html) 欢迎大家加入“专注Silverlight”QQ技术群,欢迎大家加入一起学习讨论Silverlight&WPF&Widnows Phone开发技术。  22308706(一群) 超级群500人  37891947(二群) 超级群500人  100844510(三群) 高级群200人  32679922(四群) 超级群500人  23413513(五群) 高级群200人  32679955(六群) 超级群500人  61267622(七群) 超级群500人  88585140(八群) 超级群500人  128043302(九群 企业应用开发推荐群) 高级群200人  101364438(十群) 超级群500人  68435160(十一群 企业应用开发推荐群)超级群500人
';

Navigation导航框架开篇

最后更新于:2022-04-01 14:21:10

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在Web或者Windows传统应用项目中,导航功能是基础功能之一,其目的是将用户目标和应用业务目标协调综合起来,从而帮助用户能够快捷的浏览信息和获取服务。一个友好的导航功能不仅仅能够提高用户的阅读效率,而且还能反映其项目品牌形象以及影响其品牌可信度。在Silverlight中,导航框架(Navigation Framework)是Silverlight核心框架之一,其功能与传统Web和Windows应用导航功能类似。在随后的几篇文章中,详细学习Silverlight导航框架的原理和实例应用,希望通过这套系列教程,帮助Silverlight开发人员理解和掌握Silverlight Navigation Framework。 **Silverlight导航框架概述** 在传统导航功能中,经常会出现以下几个技术特征: 1.   能够记录浏览历史信息;当用户点击某个链接后,跳转到下一个功能页面,而导航功能能够记录访问浏览过的信息链接,通过“前进”或“后退“按钮能够轻松的返回到上一个访问页面; 2. 支持通过URL进行传参,特别是在Web应用项目中,在导航过程中,使用URL进行传递参数是最常用的功能;例如:从浏览用户信息页面,跳转到编辑用户信息页面,可以通过URL传递用户ID到编辑页面,是其能够通过该ID读取到数据库中指定用户信息; 在Silverlight 3之前的版本,Silverlight没有特定的导航框架,项目中页面之间的切换是通过修改RootVisual布局容器的内容而实现的。在后文将详细介绍早期页面导航的方法和步骤。 ~~~ private void Application_Startup(object sender, StartupEventArgs e) {     this.RootVisual = new MainPage(); } ~~~ 在Silverlight 3版本中, 微软推出Navigation Framework导航框架,同时推出Silverlight Navigation应用模板,帮助开发人员创建Silverlight导航应用。 在导航框架中,不仅实现了传统导航功能,而且加入了许多独特的新特性。例如,地址映射,浏览器集成导航等。为了加大Navigation Framework的灵活性,在Silverlight 4中,增加新的属性和接口允许开发人员创建扩展导航功能。在随后的几篇中,我们将详细讲解这些导航功能应用和实例。 **Silverlight导航框架应用方案** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cf1ae3a.png) 1.    **应用项目内部导航**; Silverlight项目内部导航是导航框架主要功能之一,导航框架提供Frame和Page控件类控制Silverlight项目页面承载以及页面导航切换功能。其中Frame类如同一个页面容器控件,用于协助导航页面的切换和显示;而Page类用于承载具体内容页面。 2.    **应用项目外部导航**; 应用项目外部导航是指导航框架支持应用程序外部资源的直接访问链接。 Silverlight导航框架支持开发人员通过EnableNavigation属性设置是否允许外部导航功能,同时支持HyperlinkButton控件导航页面到应用外部资源。例如: <HyperlinkButton NavigateUri="http://www.silverlight.net" Content="访问Silverlight官方网站" TargetName="_new" /> ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cf341c4.png) 3.    **Web浏览器集成导航**; Silverlight是基于Web浏览器的富应用插件,对于其页面导航切换,可以被集成到浏览器导航功能中。通过设置Silverlight导航框架JournalOwnership属性可以指定是否将当前应用与Web浏览器导航相集成,而在默认情况下,JournalOwership属性值为Automatic,表示当前框架为顶级框架时,将于浏览器导航集成在一起;而当属性值设置为OwnsJournal时,则表示禁止浏览器集成导航功能,当前应用导航框架内部保留导航日志。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cf42fb6.png) 值得注意的是,Web浏览器集成导航功能和浏览器版本相互关联,在Internet Explorer 7之前的版本,如果需要浏览器支持集成导航功能,需要在Silverlight承载页面中添加一个名为“_sl_historyFrame”的iFrame框架,该框架将记录应用浏览记录。从Internet Explorer 8开始以及随后的版本,在不需要该框架支持的情况下,也可以记录应用浏览记录。这是因为在Internet Explorer 7之前的版本无法对当前Javascript API中location.hash对象进行更新,在hash标签没有更新的情况下,浏览器会默认处于当前位置,不会生成浏览历史记录,Internet Explorer 8之后的版本已经不存在这个问题。 4.    **应用扩展导航系统**; 虽然Silverlight导航框架提供强大的应用内部,外部以及浏览器集成导航功能,但是在实际项目中,仍旧存在不灵活的弊端。为了使Silverlight导航框架更加灵活多变,在Silverlight 4中,导航框架提供一个新的属性和接口ContentLoader和INavigationContentLoader,允许开发人员创建应用扩展导航功能。 在随后的章节中将对以上功能详细讲解和演示。在Silverlight 5中导航功能没有较多的更新,只是在其原有基础上对其性能进行了优化,下图为导航框架在Silverlight各版本中的特点更新: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cf5868f.png) **Silverlight导航框架优势** Silverlight导航框架优势可总结如下: 1.    简洁API接口,降低使用复杂度,减少开发工作量,同时方便开发人员日常维护; 2.    导航框架能够记录历史浏览信息,通过浏览器“前进”或“后退”按钮,可以轻松访问上一次访问的页面; 3.    能够支持URL传参功能,特别是在Web应用项目中,在导航过程中,使用URL进行传递参数是最常用的功能;例如:从浏览用户信息页面,跳转到编辑用户信息页面,可以通过URL传递用户ID到编辑页面,是其能够通过该ID读取到数据库中指定用户信息; 4.    支持深度链接(Deep Link),可通过链接访问不同页面状态下的应用; 曾经有开发人员询问过,什么是Deep Link?这里给出简单的解释: 深度链接(Deep Link)是指项目中一个特定页面或者资源的超级链接地址,该链接保存某特定的状态,可被直接定位访问。例如:[http://www.silverlight.net/index.html](http://www.silverlight.net/index.html)是主页链接,而http://www.Silverlight.net/contact.html则是该网站的一个深度链接,通过该地址可以直接定位到联系页面;或者http://www.silverlight.net/image/logo.gif,该图片资源的地址同样是一个深度链接。在后文,将详细演示和介绍Deep Link的应用。 更多Silverlight实例教程系列: [Silverlight实例教程系列 - Silverlight Validation验证实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html) [Silverlight实例教程系列 - Silverlight Out-of-Browser实例](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0809/1709.html) [Silverlight实例教程系列 - Expression Blend实例中文教程](http://silverlightchina.net/html/zhuantixilie/getstart/2010/0409/978.html) 欢迎大家加入“专注Silverlight”QQ技术群,欢迎大家加入一起学习讨论Silverlight&WPF&Widnows Phone开发技术。  22308706(一群) 超级群500人  37891947(二群) 超级群500人  100844510(三群) 高级群200人  32679922(四群) 超级群500人  23413513(五群) 高级群200人  32679955(六群) 超级群500人  61267622(七群) 超级群500人  88585140(八群) 超级群500人  128043302(九群 企业应用开发推荐群) 高级群200人  101364438(十群) 超级群500人  68435160(十一群 企业应用开发推荐群)超级群500人
';

自定义扩展Validation类,验证框架的总结和建议

最后更新于:2022-04-01 14:21:08

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) [Silverlight Validation验证实例教程系列](http://www.silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html)已经写了[七篇](http://www.cnblogs.com/jv9/)了,今天将完成计划中的最后一个话题,创建自定义扩展验证类,本篇是根据一些读者反馈的问题总结而来的,在本篇最后,将简单的对目前Silverlight Validation验证框架提供的验证机制进行总结性的对比和归纳,希望能够帮助大家在实际项目中定位和应用验证框架。 阅读过[前几篇Silverlight实例教程](http://www.silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html)的朋友,给我留言和来信,大家对于Silverlight Validation类的使用,总感觉有些不灵活,特别是在自定义使用时,很难轻松的控制错误验证的捕获和弹出。 下面,我将演示另外一个实例,该实例将帮助开发人员创建自定义扩展Validation类,该类允许开发人员,方便的控制验证错误弹出,验证错误清除,以及验证校验方法。 **Silverlight Validation自定义扩展类** 本实例仍旧使用SilverlightValidationDemo项目,在Mainpage中创建一个简单的UI,进行演示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cedf779.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_D5A9/image_2.png) ~~~ <StackPanel Margin="5">                   <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="产品名: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtProduct" Width="200" />              </StackPanel>              <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="数  量: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtAmount" Width="200"  />              </StackPanel>              <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="单  价: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtPrice" Width="200" />              </StackPanel>              <StackPanel Orientation="Horizontal" >                  <Button x:Name="btBuy" Content="购  买" Margin="5" />                  <Button x:Name="btReset" Content="重  置" Margin="5" />              </StackPanel>  </StackPanel> ~~~ 根据上图,我们看到,我们将对产品名,产品数量和产品单价进行验证,在Xaml代码中,没有对Text进行绑定,这些,我们将在代码中进行实现。 在完成上面UI的创建,我们需要创建一个静态类ValidationExtension,在该类中,我们将创建自定义验证方法,以及验证错误信息控制方法。 在ValidationExtension类中,我们将使用以下三个静态方法,接管Silverlight Validation默认的验证捕获,其代码分别是: ~~~ public static void SetValidation(this FrameworkElement frameworkElement, string message)  {              CustomizeValidation customValidation = new CustomizeValidation(message);              Binding binding = new Binding("ValidationError")              {                  Mode = System.Windows.Data.BindingMode.TwoWay,                  NotifyOnValidationError = true,                  ValidatesOnExceptions = true,                  Source = customValidation              };              frameworkElement.SetBinding(Control.TagProperty, binding);  } ~~~ SetValidation静态方法,将设置FrameworkElement元素绑定ValidationError验证错误信息,其中设置NotifyOnValidationError 和ValidatesOnExceptions 为True,允许控件对异常和验证错误进行捕获和反馈。 ~~~ public static void RaiseValidationError(this FrameworkElement frameworkElement)          {              BindingExpression b = frameworkElement.GetBindingExpression(Control.TagProperty);              if (b != null)              {                  ((CustomizeValidation)b.DataItem).ShowErrorMessage = true;                  b.UpdateSource();              }          } ~~~ RaiseValidationError静态方法,在验证错误绑定后,通过该方法将错误异常显示在客户端,通过UpdateSource方法更新客户端错误异常显示。简单的理解就是在客户端控件对象,弹出异常错误提示信息。 ~~~ public static void ClearValidationError(this FrameworkElement frameworkElement)          {              BindingExpression b = frameworkElement.GetBindingExpression(Control.TagProperty);              if (b != null)              {                  ((CustomizeValidation)b.DataItem).ShowErrorMessage = false;                  b.UpdateSource();              }          } ~~~ ClearValidationError静态方法,和RaiseValidationError静态方法正好相反,调用该方法将清空当前对象上显示的异常错误信息。 以上三个方法的调用,将在后文演示。下面需要添加简单的验证条件,帮助客户端捕获验证错误信息,为了方便起见,这里,创建了对数字的判断和对双精度型的数据判断,代码如下: ~~~ public static bool IsNumberValid(this string inputNumber)          {              bool isNumberValid = true;              int number = -1;              if (!Int32.TryParse(inputNumber, out number))              {                  isNumberValid = false;              }              return isNumberValid;          }  ~~~ IsNumberValid静态方法,判断当前对象中输入字符是否为数字; ~~~ public static bool IsPriceValid(this string inputPrice)          {              bool isPriceValid = true;              double minprice = 8.8;              if (Convert.ToDouble(inputPrice) < minprice)              {                  isPriceValid = false;              }              return isPriceValid;          }  ~~~ IsPriceValid静态方法,判断当前对象中输入字符是否大于最小价格,如果False,则返回验证错误。 这里大家已经留意到,ValidationExtension自定义扩展类没有继承和实现任何验证类或接口,独立存在。 在以上静态方法中,我们用到了CustomizeValidation自定义验证类中的属性成员,在过去的几篇中,我们仅在CustomizeValidation中定义了一个简单的自定义验证方法,而现在我们需要添加两个简单的属性和一个新的构造函数,其代码如下: ~~~ #region Private memebers          private string message;          #endregion          #region Public Property          public bool ShowErrorMessage          {              get;              set;          }          public object ValidationError          {              get              {                  return null;              }              set              {                  if (ShowErrorMessage)                  {                      throw new ValidationException(message);                  }              }          }  #endregion ~~~ 构造函数: ~~~ public CustomizeValidation(string message)          {              this.message = message;          } ~~~ 其目的是为了收集验证错误信息。 完成了以上自定义代码后,我们可以在客户端进行简单的调用代码设置: 目前,我们希望,点击“购买”按钮后,对用户输入信息进行验证判断,如果有错误异常,则弹出验证错误信息, 这里我们仅需要添加部分代码到btBuy.Click事件即可。 ~~~ #region Validation Extension          private void btBuy_Click(object sender, RoutedEventArgs e)          {              bool isValid = true;              txtProduct.ClearValidationError();              txtAmount.ClearValidationError();              txtPrice.ClearValidationError();              if (txtProduct.Text == "")              {                  txtProduct.SetValidation("请输入产品名称");                  txtProduct.RaiseValidationError();                  isValid = false;              }              if (txtAmount.Text == "" || !txtAmount.Text.IsNumberValid())              {                  txtAmount.SetValidation("请输入一个整数");                  txtAmount.RaiseValidationError();                  isValid = false;              }              if (txtPrice.Text == "" || !txtPrice.Text.IsPriceValid())              {                  txtPrice.SetValidation("最小出价8.8");                  txtPrice.RaiseValidationError();                  isValid = false;              }              if (isValid)              {                  HtmlPage.Window.Alert("产品购买成功");                  ResetForm();              }          }          private void btReset_Click(object sender, RoutedEventArgs e)          {              ResetForm();          }          private void ResetForm()          {              txtProduct.ClearValidationError();              txtAmount.ClearValidationError();              txtPrice.ClearValidationError();              txtProduct.Text = "";              txtAmount.Text = "";              txtPrice.Text = "";          }  #endregion ~~~ 通过SetValidation,设置验证错误提示信息,通过RaiseValidationError弹出验证错误信息,每次点击前,调用ClearValidationError清空当前验证错误。最终执行结果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cef0edd.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_D5A9/image_4.png) 到这里,我们已经完成了一个自定义扩展Validation类,大家可以根据这个思路扩展更多的验证校验方法,并应用到项目控件中。 **Silverlight Validation验证机制对比总结和建议** 在过去的几篇中,我们曾经详细介绍了四种Silverlight Validation验证机制,分别是 基本异常验证机制; DataAnnotation验证机制; IDataErrorInfo客户端同步验证机制; INotifyDataErrorInfo服务器端异步验证机制; 一些朋友发邮件问我,这些验证机制在项目中的优势是什么?在实际项目中,如何选择适当的验证机制?下面有个简单的列表,将以上四种验证机制进行简单的归纳总结: <table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td width="130"><p align="center"><strong>验证机制</strong></p></td><td width="237"><p align="center"><strong>优势</strong></p></td><td width="183"><p align="center"><strong>劣势</strong></p></td></tr><tr><td width="130"><p>基本异常验证机制</p></td><td width="237"><p>1. 适用任何数据类型验证;</p><p>2. 使用方法简单,仅需在Xaml代码中设置即可;</p></td><td width="183"><p>1. 只能在属性Setter中使用;</p><p>2. 不支持自定义方法验证</p><p>3. 每个成员每次仅能捕获一个验证错误</p></td></tr><tr><td width="130"><p>DataAnnotation验证机制</p></td><td width="237"><p>1. 不会引发异常错误;</p><p>2. 每个成员可以使用多个验证条件;</p><p>3. 使用方法简单,仅需声明属性即可;无需过多编写代码;</p><p>4. 支持自定义方法验证;</p></td><td width="183"><p>仅适合用于Datagrid和Dataform和一些可使用DataAnnotation属性的第三方控件</p></td></tr><tr><td width="130"><p>IDataErrorInfo客户端同步验证机制</p></td><td width="237"><p>1. 不会引发异常错误;</p><p>2. 支持自定义方法验证;</p></td><td width="183"><p>1. 不能捕获数据类型验证错误;</p><p>2. 每个数据成员每次仅能捕获一个验证错误;</p><p>3. 使用方法较为复杂;</p></td></tr><tr><td width="130"><p>INotifyDataErrorInfo服务器端异步验证机制</p></td><td width="237"><p>1. 不会引发异常错误;</p><p>2. 支持自定义方法验证;</p><p>3. 支持服务器端异步验证;</p><p>4. 每个成员可以使用多个验证条件;</p></td><td width="183"><p>1. 不能捕获数据类型验证错误;</p><p>2. 多条件验证下,仅支持显示第一个验证错误;</p><p>3. 使用方法复杂;</p></td></tr></tbody></table>   在使用Silverlight Validation框架是需要注意以下几点:   1. 使项目支持异常捕获,这样验证框架可支持数据类型校验; 2. 如果使用Datagrid和Dataform控件,推荐使用DataAnnotation验证机制; 3. 如果需要在客户端验证所有信息,推荐使用IDataErrorInfo验证机制; 4. 如果需要使用服务器端的验证方法,推荐使用INotifyDataErrorInfo验证机制。   相信大家在明白了以上各个验证机制的优势和劣势后,已经可以轻松掌握Silverlight Validation验证框架的应用了。 [Silverlight Validation实例教程系列](http://www.silverlightchina.net/html/zhuantixilie/getstart/2010/0924/2035.html),到这里即将完结,如果大家在阅读中,或者项目中遇到问题或者有不同的意见, 欢迎留言给我,我们一起讨论学习。 最后感谢每一位支持的朋友。 [源代码下载](http://www.silverlightchina.net/resource/code/2010/SilverlightValidationDemo.rar) 欢迎大家加入“专注Silverlight”QQ技术群,目前,1-6群都已经满员,新开500人七群,欢迎大家加入一起学习讨论Silverlight&WPF开发技术。  22308706(一群) 超级群500人满  37891947(二群) 超级群500人满  100844510(三群) 高级群200人满  32679922(四群) 超级群500人满  23413513(五群) 高级群200人满  32679955(六群) 超级群500人满  61267622(七群 推荐) 超级群500人未满  
';

Datagrid,Dataform数据验证和ValidationSummary

最后更新于:2022-04-01 14:21:06

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 上一篇,我们讨论了,捕获用户提交数据验证。本篇将集中讨论Datagrid和Dataform两个数据控件的数据验证方法,其中,我们会附加介绍一个新的验证控件ValidationSummary。 **概述** Datagrid和Dataform是Silverlight中最常用的两个数据控件,其主要目的是作为数据集合的载体控件。这两个控件不仅支持自动数据绑定,而且允许用户添加许多自定义行为操作,例如编辑,排序,删除,添加等。而在日常项目开发中,经常会碰到用户在编辑,或者添加时对数据的验证判断,在数据commit前,即捕获数据异常并返回提示信息到客户端。 **ValidationSummary控件** 在Datagrid和Dataform数据验证中,最为常用的是[ValidationSummary控件](http://msdn.microsoft.com/en-us/library/system.windows.controls.validationsummary(VS.95).aspx),该控件和WebForm中的ValidationSummary控件类似,其功能都是将错误信息集合显示在一个ListBox控件中。简单的说,ValidationSummary控件是一个能够容纳验证错误集合的容器,能够检测和显示当前页面所有验证结果到客户端。 **命名控件**:System.Windows.Controls **装配**:System.Windows.Controls.Data.Input (位于 System.Windows.Controls,Data.Input.dll) 我们仍旧使用上一篇的源代码项目,SilverlightValidationDemo,简单修改代码如下: 首先需要添加新的命名空间引用, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cddd2bc.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/Image00704_2.jpg) 然后添加ValidationSummary控件,即可 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce017cb.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/Image00706_2.jpg) 其运行结果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce17f9e.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_2.png) 这样就一个ValidationSummary使用实例。细心的朋友可能已经发现,上图,一共出现了八处验证错误提示,而在ValidationSummary中,仅显示了四个。这里需要对此进行简单的**说明**, 1. 如果使用ValidationSummary控件捕获验证错误,必须将Mode设置为Twoway; 2. 如果使用ValidationSummary控件捕获验证错误,必须将ValidatesOnExceptions设置为True; 3. 如果使用ValidationSummary控件捕获验证错误,必须将NotifyOnValidationError设置为True; 在我们原有的代码中,都没有满足以上条件,所以ValidationSummary忽略其验证错误信息。参考代码如下: ~~~ <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="邮   件: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtEmail" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=email, Mode=TwoWay, ValidatesOnNotifyDataErrors=False, NotifyOnValidationError=True, ValidatesOnExceptions=True}" />             </StackPanel>             <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="地   址: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtAddress" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=address, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=False, ValidatesOnExceptions=True}" />             </StackPanel>             <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="电   话: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtPhone" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=phone, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=False, ValidatesOnExceptions=True}" />             </StackPanel>             <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="成绩等级: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtGradeLevel" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=gradelevel, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=False, ValidatesOnExceptions=True}" />             </StackPanel>             <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="成绩范围: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtGradeRange" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=graderange, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=False, ValidatesOnExceptions=True}" />             </StackPanel> ~~~ ValidationSummary控件,提供了许多属性,允许开发人员自定义其调用,例如,如果不想让ValidationSummary控件捕获显示UserName用户名验证错误,只需在代码中添加,dataInput:ValidationSummary.ShowErrorsInSummary = “False”,就可以了。 ~~~ <StackPanel Orientation="Horizontal" Margin="5" x:Name="spUsername">                  <TextBlock Text="用户名: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtUserName" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=Name, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True,UpdateSourceTrigger=Explicit}" dataInput:ValidationSummary.ShowErrorsInSummary = "False"/>  </StackPanel> ~~~ 在明白了ValidationSummary控件的使用后,我们来看看Datagrid数据验证的使用。 **Datagrid数据验证** Datagrid控件的主要功能是将数据集合使用表格的方式展示到客户端。该控件支持大量的属性和事件,允许用户对数据集合进行操作,例如修改数据,添加数据,删除等操作。在这些操作中,数据验证也是最常用的功能之一。为了演示该实例,我们将添加一个简单的数据集合和一个Datagrid控件,并将该数据集合绑定到Datagrid控件, 在User数据成员类中,定义一个新的构造函数: ~~~ public User(string strname,string strpwd,int iage,string stremail)  {      Name = strname;      password = strpwd;      Age = iage;      email = stremail;  } ~~~ 在MainPage中,添加新的命名空间引用: xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" 然后,添加一个datagrid控件, ~~~ <data:DataGrid x:Name="dgValidationDemo"                             AutoGenerateColumns="False"                             Margin="10" Width="350"                             HorizontalAlignment="Left"                             >                  <data:DataGrid.Columns>                      <data:DataGridTextColumn Header="用户名" Binding="{Binding Name,Mode=TwoWay}"/>                      <data:DataGridTextColumn Header="密码" Binding="{Binding password,Mode=TwoWay}" />                      <data:DataGridTextColumn Header="年龄" Binding="{Binding Age,Mode=TwoWay}"/>                      <data:DataGridTextColumn Header="电子邮件" Binding="{Binding email,Mode=TwoWay}" />                  </data:DataGrid.Columns>  </data:DataGrid> ~~~ 在MainPage后台代码中,添加数据集合初始化代码: ~~~         private List<User> InitCollection()          {              List<User> tmpUserCollection = new List<User>();              tmpUserCollection.Add(new User("jv9", "123456", 99, "qq34506@hotmail.com"));              tmpUserCollection.Add(new User("冷秋寒", "654321", 88, "admin@hotmail.com"));              tmpUserCollection.Add(new User("Silverlight", "666666", 77, "silverlight@hotmail.com"));              tmpUserCollection.Add(new User("银光中国", "888888", 66, "admin@silverlightchina.net"));              return tmpUserCollection;          } ~~~ 然后在MainPage页面构造函数中,进行数据绑定: dgValidationDemo.ItemsSource = InitCollection(); 运行即可看到如下图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce2d925.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_4.png) Silverlight Datagrid的数据验证大体可分为两种:单元格数据验证和数据行验证;下面我们使用实例演示讲解着两种验证方法, **1. 单元格数据验证** 单元格数据验证,顾名思义,是对Datagrid中的某一个单元格进行Validation。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce3dd60.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_6.png) 这种验证可以基于前几篇中的四种验证机制对数据进行判断,最为常用的验证机制方式为:基本异常验证和DataAnnotation验证机制。 **2. 行数据验证** 行数据验证,其功能性和单元格数据验证相同,而其验证作用范围是被验证数据整行。当行数据验证出现错误时,则会在Datagrid底部显示一个ListBox显示其错误信息,其样式和ValidationSummary相似,点击ListBox错误信息,即可跳入验证出错行。 这时会发现,出现验证错误整行背景成为粉红色,而出错的单元格,不再显示红框验证错误提示,其错误信息被显示在Datagrid底部。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce4e285.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_8.png) 行数据验证和单元格数据验证最大的不同,是其锁定的范围不同。当使用行数据验证时,尽管当前单元格验证有错误,用户仍旧可以继续修改该行中其他数据单元格,其焦点被锁定在整行;而单元个验证,则被锁定在某一个单元格,数据验证报错,用户无法切换焦点,必须纠正验证错误后,才能继续下一步操作。 [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_10.png) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce6113c.jpg) **DataForm数据验证** DataForm数据控件是Silverlight 3 Toolkit中推出的数据处理表格控件。该控件可将数据集合成员显示到客户端。其中自带添加,修改,删除等内建功能。 由于使用该控件需要对数据集合成员进行绑定,每次绑定就已经将Validation验证框架应用Dataform中,每当验证错误出现时,DataForm控件将自动捕获验证错误,并显示在客户端。 使用该控件需要添加以下命名空间引用: xmlns:dataform="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit" 我们在MainPage中,添加DataForm控件代码 ~~~ <dataform:DataForm x:Name="dfDetail"                                 Margin="10" Width="350" Height="300"                                 HorizontalAlignment="Left"                                 AutoGenerateFields="False"                                 ItemsSource="{Binding}">                  <dataform:DataForm.EditTemplate>                      <DataTemplate>                          <StackPanel>                              <dataform:DataField>                                  <StackPanel Orientation="Horizontal">                                      <TextBlock Text="用户名: " VerticalAlignment="Center"/>                                      <TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True}" VerticalAlignment="Center" Width="100"/>                                  </StackPanel>                              </dataform:DataField>                              <dataform:DataField>                                  <StackPanel Orientation="Horizontal">                                      <TextBlock Text="密码: " VerticalAlignment="Center"/>                                      <TextBox Text="{Binding password, Mode=TwoWay, ValidatesOnDataErrors=True}" VerticalAlignment="Center" Width="100"/>                                  </StackPanel>                              </dataform:DataField>                              <dataform:DataField>                                  <StackPanel Orientation="Horizontal">                                      <TextBlock Text="年龄: " VerticalAlignment="Center"/>                                      <TextBox Text="{Binding Age, Mode=TwoWay, ValidatesOnDataErrors=True}" VerticalAlignment="Center" Width="100"/>                                  </StackPanel>                              </dataform:DataField>                              <dataform:DataField>                                  <StackPanel Orientation="Horizontal">                                      <TextBlock Text="电子邮件: " VerticalAlignment="Center"/>                                      <TextBox Text="{Binding email, Mode=TwoWay, ValidatesOnDataErrors=True}" VerticalAlignment="Center" Width="100"/>                                  </StackPanel>                              </dataform:DataField>                          </StackPanel>                      </DataTemplate>                  </dataform:DataForm.EditTemplate>  </dataform:DataForm> ~~~ 在DataForm中,我们对已知数据成员进行绑定设置。下面需要简单修改Mainpage后台代码,将数据集合绑定到DataForm: ~~~         public MainPage()          {              InitializeComponent();              //dgValidationDemo.ItemsSource = InitCollection();              PagedCollectionView pcv = new PagedCollectionView(InitCollection());              spDataCollection.DataContext = pcv;          } ~~~ 这里我们使用了[PagedCollectionView 类](http://msdn.microsoft.com/en-us/library/system.windows.data.pagedcollectionview(VS.95).aspx),将原有的List<User>转换为PagedCollectionView ,将其绑定到spDataCollection布局控件的DataContext,从而实现该布局下所有数据控件ItemsSource共同绑定同一个数据源。当Datagrid选择项被修改时,DataForm当前项也同时修改。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce844ae.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_12.png) 这时,我们可以对DataForm进行简单的验证测试: 当我们点击添加一行新数据时,保持所有TextBox为空,点击Submit,则会看到Dataform返回的验证错误信息提示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ce999ae.jpg) [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_14.png) 这时,数据集合已经被锁定,无论是Datagrid还是Dataform都无法做任何数据操作。 [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_8E18/image_16.png) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cebd7fe.jpg) 以上可以看出,对于Dataform的数据验证,开发人员无需进行过多的干涉,Validation验证框架会自动接管其验证进程。 Ok,今天的内容就讲到这里,希望大家能有所收获。 [源代码第一部分下载](http://www.silverlightchina.net/uploads/soft/100922/1-100922145T2.rar) [源代码第二部分下载](http://www.silverlightchina.net/uploads/soft/100922/1-100922150230.rar) 欢迎大家加入“专注Silverlight”QQ技术群,目前,1-6群都已经满员,新开500人七群,欢迎大家加入一起学习讨论Silverlight&WPF开发技术。 22308706(一群) 超级群500人满 37891947(二群) 超级群500人满 100844510(三群) 高级群200人满 32679922(四群) 超级群500人满 23413513(五群) 高级群200人满 32679955(六群) 超级群500人满 61267622(七群 推荐) 超级群500人未满
';

Validation用户提交数据验证捕获

最后更新于:2022-04-01 14:21:03

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在以往的Validation系列中,介绍了四种Silverlight验证机制: 1. 基本异常验证机制; 1. DataAnnotation验证机制; 1. IDataErrorInfo客户端同步验证机制; 1. INotifyDataErrorInfo服务器端异步验证机制; 在每篇的实例中,大家都能发现这几种Silverlight Validation机制是根据异常主动触发的验证机制。本文将介绍另外一种常用验证方法,该验证方法是基于以上四种验证机制,我们称之为被动型触发验证。 **概述** 被动型触发验证,简单的理解,就是当用户交互时,通过用户行为被动激活Validation验证机制。简单的例子,一个需要注册用户的页面, 其表格中,没有任何填写数据,而初始化后,对该表格不进行验证处理,仅当用户点击“注册”按钮后,对需要填写的控件进行验证判断,这时就需要用到被动型触发验证。 **UpdateSourceTrigger属性** [UpdateSourceTrigger属性](http://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger.aspx)是Validation数据验证的重要属性之一,该属性主要表示数据源触发更新的执行时间。主要运用在Binding中,例如 ~~~ <TextBox  Text="{Binding Username, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, UpdateSourceTrigger=Explicit}"/> ~~~ 通过MSDN,我们可以了解到UpdateSourceTrigger属性有两个值, 1. Default,该值返回目标依赖属性的默认UpdateSourceTrigger值,多数控件返回的默认值为PropertyChanged,而Text属性的默认值为LostFocus。 2. Explicit,如果设置UpdateSourceTrigger属性设置为显式方式,则需要开发人员手工调用UpdateSource方法,才能对数据源更新事件进行触发,否则不做任何操作。 在默认情况下,UpdateSourceTrigger属性为Default。这也就是尽管在前几篇的实例中,在Binding中,我们没有设置任何PropertyChanged信息,仍旧能够触发验证。 当数据绑定被修改后,绑定会自动触发UpdateSourceTrigger属性,通过该属性,对绑定数据源的数据成员进行验证,如果有异常,则返回False,反之为True。 **提交数据验证捕获实例** 在文章开始,我们介绍了被动型触发验证方法,该方法在实际项目中是常用功能之一。前文提及的一个例子,注册时,想要在用户点击“注册”按钮时对所有填写值使用Validation功能进行判断, 其实现方法则需要将UpdateSourceTrigger属性设为Explicit,在后台中,我们使用代码控制其验证,通过这种方法,对提交数据进行验证捕获操作。 下面的例程,我们仍旧使用SilverlightValidationDemo项目,如果你没有该项目,可以到[上一篇](http://www.cnblogs.com/jv9/archive/2010/09/15/1826547.html)下载该项目源代码, 在本例中,我们将尝试点击提交注册按钮,但是在点击“注册”时,对姓名,密码和年龄进行验证判断。在没有对代码修改前,点击“注册”按钮,页面不会捕获任何数据提交验证, 我们将对姓名,密码和年龄代码进行简单修改 ~~~ <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="用户名: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtUserName" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}"  Text="{Binding Path=Name, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True,UpdateSourceTrigger=Explicit}" />              </StackPanel>              <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="密   码: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtPassword" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}"  Text="{Binding Path=password, Mode=TwoWay,ValidatesOnExceptions=True, NotifyOnValidationError=True,UpdateSourceTrigger=Explicit}" />              </StackPanel>              <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="年   龄: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtAge" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}"  Text="{Binding Path=Age, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True,UpdateSourceTrigger=Explicit}" />              </StackPanel> ~~~ 从上面代码可以看出,我们在Binding中,添加UpdateSourceTrigger=Explicit,根据上文提示,我们必须手工对数据源进行更新触发。 这里需要解释一点,如果UpdateSourceTrigger=Default,当绑定模式为Twoway时,TextBox失去焦点,则会触发数据源更新, 这一切都有Silverlight API控制,而我们设置UpdateSourceTrigger=Explicit后,则由开发人员控制。 UpdateSourceTrigger设置为Explicit后,我们需要手动调用UpdateSource,才能对数据源进行验证。 在UpdateSource前,我们需要使用代码获取到绑定对象的实例。获取绑定对象实例,需要使用到[BindingExpression类](http://msdn.microsoft.com/en-us/library/system.windows.data.bindingexpression.aspx),BindingExpression类中包含了一个绑定对象实例的所有信息。 而获取一个BindingExpression对象,则需要使用GetBindingExpression方法,对验证目标对象属性进行捕获。 例如,我们实例中的代码: ~~~ BindingExpression beUsername = txtUserName.GetBindingExpression(TextBox.TextProperty);  beUsername.UpdateSource(); ~~~ 通过txtUserName.GetBindingExpression获取TextBox对象的TextProperty绑定属性,然后赋值到beUsername。 然后调用UpdateSource方法,实现手工更新数据源,同时,数据源的修改,自然也就被动激活了后台的验证机制。 在实际项目中,仅获取到了验证错误信息,还是不够的,页面还是会继续进行下一步流程代码,而这里,我们将会使用Validation类中的方法和属性,对验证错误进行简单的判断, ~~~ private void btReg_Click(object sender, RoutedEventArgs e)  {      BindingExpression beUsername = txtUserName.GetBindingExpression(TextBox.TextProperty);      beUsername.UpdateSource();      if (Validation.GetHasError(txtUserName))          return;  } ~~~ 上面代码,使用Validation类中的GetHasError()方法确认验证是否有错误,如果有,则返回空,UI的Validation机制将会接管前台验证错误显示,而后台,则会忽略该点击事件操作。 如果你想获取跟为详细的验证错误信息提示,可以通过Validation类中的GetErrors()方法枚举出所有被捕获的验证错误信息。 ~~~ List<ValidationError> errors = new List<ValidationError>();  foreach (ValidationError erroritem in Validation.GetErrors(txtUserName))  {       errors.Add(erroritem);  } ~~~ [](http://images.cnblogs.com/cnblogs_com/jv9/WindowsLiveWriter/SilverlightValidation_A8DB/Image00701_2.jpg)![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cdaba11.jpg) 最终注册提交代码如下: ~~~         private void btReg_Click(object sender, RoutedEventArgs e)         {             BindingExpression beUsername = txtUserName.GetBindingExpression(TextBox.TextProperty);             beUsername.UpdateSource();             BindingExpression bePassword = txtPassword.GetBindingExpression(TextBox.TextProperty);             bePassword.UpdateSource();             BindingExpression beAge = txtAge.GetBindingExpression(TextBox.TextProperty);             beAge.UpdateSource();             if (Validation.GetHasError(txtUserName))                 return;             if (Validation.GetHasError(txtPassword))                 return;             if (Validation.GetHasError(txtAge))                 return; //捕获验证错误集合演示             List<ValidationError> errors = new List<ValidationError>();             foreach (ValidationError erroritem in Validation.GetErrors(txtUserName))             {                 errors.Add(erroritem);             }         } ~~~ 其结果,点击“注册”按钮,则会提示验证错误,修改内容后,再次点击“注册”按钮,验证通过后,进入注册流程。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cdbebae.jpg)   最后需要说明一点,这种验证方法,和验证机制是无关的,无论使用哪一种验证机制,都可以使用该方法,进行用户交互数据验证。 今天就介绍到这里,希望对大家有所帮助。 [源代码下载](http://www.silverlightchina.net/uploads/soft/100920/1-100920133156.rar) 欢迎大家加入“专注Silverlight”QQ技术群,目前,1-6群都已经满员,新开500人七群,欢迎大家加入一起学习讨论Silverlight&WPF开发技术。 22308706(一群) 超级群500人满 37891947(二群) 超级群500人满 100844510(三群) 高级群200人满 32679922(四群) 超级群500人满 23413513(五群) 高级群200人满 32679955(六群) 超级群500人满 61267622(七群 推荐) 超级群500人未满
';

Validation客户端同步数据验证

最后更新于:2022-04-01 14:21:01

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 前文介绍过Silverlight Validation中两个数据验证机制,[ValidatesOnExceptions异常捕获验证机制](http://www.cnblogs.com/jv9/archive/2010/09/09/1821891.html)和[DataAnnotation验证机制](http://www.cnblogs.com/jv9/archive/2010/09/10/1822910.html),这两种验证机制,是在Silverlight 3 Validation Framework推出的,其运行方式类似,都是当异常抛出后,应用对异常信息进行捕获,并显示在客户端。在Silverlight 4中,Silverlight Validation有相对的改进,本篇将介绍Silverlight 4中新加入的验证机制功能,IDataErrorInfo客户端同步验证机制。 **Silverlight 4 IDataErrorInfo接口概述** 相信熟悉WPF的开发人员都知道,WPF也具有IdataErrorInfo接口,其接口可以无需抛出任何异常,即可对数据进行验证。而Silverlight的IDataErrorInfo接口就是从WPF中转化来的。与前面两种验证机制相比,Silverlight 4 IDataErrorInfo提供的同步验证方式,不再需要基于异常抛出的基础上来激活验证,简单的理解,就是当值验证失败的时候,不会抛出任何异常信息。这种验证机制,相对前两种验证机制来说更加灵活。 **Silverlight 4 IDataErrorInfo接口类成员** [IDataErrorInfo接口](http://msdn.microsoft.com/en-us/library/system.componentmodel.idataerrorinfo.aspx),位于System.ComponentModel命名空间。该接口主要被应用在需要对其进行验证的数据成员类。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-11-02_56374111ddec5.gif) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-17_56c4396b79c3e.gif) 代码 ~~~           #region IDataErrorInfo Members           public string Error           {               get { throw new NotImplementedException(); }           }           public string this[string columnName]  9         {              get { throw new NotImplementedException(); }         }          #endregion ~~~ IDataErrorInfo接口具有两个**属性**: 1. Error: 该属性为验证设置属性错误提示信息; 2. Item: 该属性为错误信息集合,其中索引值为属性名,将其对应的错误信息,设置到指定的被验证控件中; 从MSDN对IdataErrorInfo接口的解释中可以看到,IDataErrorInfo接口,没有任何事件方法被预先定义。也就是说,IDataErrorInfo接口本身不具备自动激活验证功能。简单的可以理解成为,当验证错误产生时,该错误信息不会自动捕获,然后显示到用户客户端上。解决该问题,需要引入另外一个接口[INotifyPropertyChanged](http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx)。对Silverlight早期版本熟悉的开发人员,应该对[INotifyPropertyChanged](http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx)接口并不陌生,该接口主要功能是当数据成员改变时发出通知到客户端,是Silverlight中最常用的一个接口,这里对该接口不再赘述。 ~~~ public class Customer  : INotifyPropertyChanged     public event PropertyChangedEventHandler PropertyChanged;     private void NotifyPropertyChanged(String info)     {         if (PropertyChanged != null)         {             PropertyChanged(this, new PropertyChangedEventArgs(info));         }     }     public string CustomerName     {         get         {             return this.customerNameValue;         }         set         {             if (value != this.customerNameValue)             {                 this.customerNameValue = value;                 NotifyPropertyChanged("CustomerName");             }         }     } ~~~ 在使用了[INotifyPropertyChanged](http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx)接口后,每当数据成员验证错误产生时,都会执行IDataErrorInfo接口,检测Error和Item属性。但是仅仅使用[INotifyPropertyChanged](http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx)接口,还无法正常将错误信息显示在客户端,同时也需要在客户端添加新的绑定验证属性[ValidatesOnDataErrors](http://msdn.microsoft.com/en-us/library/system.windows.data.binding.validatesondataerrors.aspx), 该属性在默认绑定情况下是False,如果使用IDataErrorInfo接口,则需要使用True,这时,客户端才会显示IDataErrorInfo接口被执行后产生的验证错误信息。 <TextBox Text="{Binding CustomerName,Mode=TwoWay,ValidatesOnDataErrors=true}" /> 讲到这里,我们可以结合前两篇讲解的绑定验证属性,来理解IDataErrorInfo接口。 使用IDataErrorInfo接口,必须结合INotifyPropertyChanged接口使用,否则UI无法获取到相对应属性的错误关联信息。 而使用IDataErrorInfo接口绑定验证属性时,在客户端控件内容绑定中使用ValidatesOnDataErrors = True, 另外,如果需要使用BindingValidationError事件,在客户端控件内容中,需要再绑定NotifyOnValidationError = True, 如果需要对异常进行捕获相应,同时,也需要绑定ValidatesOnExceptions = True。 **IDataErrorInfo接口使用实例演示** 本实例仍旧使用上一篇的实例代码,在其基础上添加对IDataErrorInfo接口的调用, 首先在User数据成员类中,执行IDataErrorInfo和INotifyPropertyChanged接口 ~~~        #region IDataErrorInfo Members         private string _dataError = string.Empty;         public string Error         {             get { return _dataError; }         }         private Dictionary<string, string> _dataErrors = new Dictionary<string, string>();         public string this[string columnName]         {             get              {                 if (_dataErrors.ContainsKey(columnName))                     return _dataErrors[columnName];                 else                     return null;             }         }         #endregion         #region INotifyPropertyChanged Members         public event PropertyChangedEventHandler PropertyChanged;         protected void NotifyPropertyChanged(string propertyName)         {             if (PropertyChanged != null)                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));         }         #endregion ~~~ 其中IDataErrorInfo中定义的Dictionary是验证错误集合。而INotifyPropertyChanged是最简单的当数据成员改变时返回通知到客户端,其中没有过多的逻辑代码。 我们使用最简单的数据成员生成一个验证错误,IDataErrorInfo捕获显示作为演示,  在User类中,添加一个Address地址数据成员, ~~~         private string _address;         public string address         {             get             {                 return _address;             }             set             {                 _address = value;             }         } ~~~ 然后在set中添加简单的逻辑代码, ~~~         private string _address;         public string address         {             get             {                 return _address;             }             set             {                 if (string.IsNullOrEmpty(value))                     _dataErrors["address"] = "地址必须填写";                 else if (value.Trim().Length < 6)                     _dataErrors["address"] = "地址至少6个字";                 else                     if (_dataErrors.ContainsKey("address"))                         _dataErrors.Remove("address");                 _address = value;                 NotifyPropertyChanged("address");             }         } ~~~ 修改前台,添加新的输入框,另外绑定输入框内容到address, ~~~ <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="地   址: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtAddress" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=address, Mode=TwoWay, ValidatesOnDataErrors=True}" /> </StackPanel> ~~~ 其运行结果为: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd73e9d.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd826ed.jpg) 下面,我们做一个较为复杂一些的数据验证, 学生成绩对应表 A   -  90-100分 B   -  80-89分 C   -  70-79分 D   -  60-69分 F   -  0-59分 在这个实例中,我们对多个数据成员进行客户端数据验证。 添加两个新数据成员,gradelevel和graderange,其中使用独立的验证函数ValidateGradeLevelandRange进行数据验证, ~~~         private string _gradelevel;         public string gradelevel         {             get { return _gradelevel; }             set             {                 if (ValidateGradeLevelandRange(value,graderange))                 {                     _gradelevel = value;                     NotifyPropertyChanged("gradelevel");                 }             }         }         private decimal _graderange;         public decimal graderange         {             get { return _graderange; }             set             {                 if (ValidateGradeLevelandRange(gradelevel, value))                 {                     _graderange = value;                     NotifyPropertyChanged("graderange");                 }             }         } ~~~ ~~~ #region Customize Validation         private bool ValidateGradeLevelandRange(string level, decimal range)         {             bool isValid = false;             if (level == null)             {                 _dataErrors["gradelevel"] = "成绩等级必须是A,B,C,D,F";                 return false;             }             else             {                 switch (level.ToUpper())                 {                     case "A":                         isValid = (range >= 90 && range <= 100);                         break;                     case "B":                         isValid = (range >= 80 && range <= 89);                         break;                     case "C":                         isValid = (range >= 70 && range <= 79);                         break;                     case "D":                         isValid = (range >= 60 && range <= 69);                         break;                     case "F":                         isValid = (range >= 0 && range <= 59);                         break;                     default:                         _dataErrors["gradelevel"] = "成绩等级必须是A,B,C,D,F";                         return false;                 }             }             if (isValid)             {                 if (_dataErrors.ContainsKey("gradelevel"))                     _dataErrors.Remove("gradelevel");                 if (_dataErrors.ContainsKey("graderange"))                     _dataErrors.Remove("graderange");             }             else             {                 _dataErrors["gradelevel"] = "成绩等级和成绩范围不符合";                 _dataErrors["graderange"] = "成绩范围和成绩等级不符合";             }             return isValid;         }         #endregion ~~~ 在前台添加两个成绩输入框, ~~~~             <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="成绩等级: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtGradeLevel" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=gradelevel, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=False, ValidatesOnExceptions=True}" />             </StackPanel>             <StackPanel Orientation="Horizontal" Margin="5">                 <TextBlock Text="成绩范围: " VerticalAlignment="Center"/>                 <TextBox x:Name="txtGradeRange" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=graderange, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=False, ValidatesOnExceptions=True}" />             </StackPanel> ~~~ 其最终运行结果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd90d76.jpg) 今天内容讲到这里了。 [源代码下载](http://silverlightchina.net/uploads/soft/100913/1_1645248331.rar) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)    
';

Validation服务器端异步数据验证

最后更新于:2022-04-01 14:20:59

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 上一篇,着重介绍了Silverlight客户端同步数据验证机制,演示了IDataErrorInfo接口的实现方法。在一些实际的Silverlight企业级项目中,我们经常会遇到通过服务对数据进行验证,另外应用在验证的同时,不会影响其他功能的运行,也就是我们常提及的异步操作,这样的需求IDataErrorInfo接口和前期我们讨论过的DataAnotation验证机制都无法实现。另外在一些项目中,开发人员会绑定多个错误到一个数据成员,而IDataErrorInfo和DataAnotation也无法实现。Silverlight 4中,微软引入一个新的接口INotifyDataErrorInfo,该接口的实现,可以轻松的解决以上两个问题。 [INotifyDataErrorInfo接口](http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifydataerrorinfo(VS.95).aspx)的概述 INotifyDataErrorInfo接口和IDataErrorInfo相同,命名空间都是System.ComponentModel。 该接口是为数据成员提供自定义的同步或者异步验证支持。最常用的是对异步验证的支持,另外,可支持单属性中绑定多个错误信息。 INotifyDataErrorInfo接口具有一个属性,一个方法,一个事件,分别是: HasErrors, 这个属性判断当前对象中是否有错误,如果返回True则说明对象出现验证错误,反之则False。 方法: GetErrors, 这个方法负责返回特定验证成员中所有的验证错误信息,如果PropertyName参数为null或者string.empty,该方法将返回一个错误到全局对象中。 事件: ErrorsChanged,该事件与上篇我们提及的PropertyChanged事件相似。当添加,删除,修改验证错误时,将激活该事件通知绑定系统,更新UI。 [INotifyDataErrorInfo接口](http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifydataerrorinfo(VS.95).aspx)实例演示 实现INotifyDataErrorInfo接口,支持服务器端异步验证,所以,本实例将创建一个Web服务,演示该接口验证效果。 本篇实例,我们仍旧使用SilverlightValidationDemo项目,为了不和过去的验证方法冲突,这里我们创建一个新的数据成员类Staff,该类实现INotifyDataErrorInfo接口和INotifyPropertyChanged接口. 其默认代码如下,后面我们将逐渐完善这些代码, ~~~        #region INotifyDataErrorInfo Members         public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;         public System.Collections.IEnumerable GetErrors(string propertyName)         {             throw new NotImplementedException();         }         public bool HasErrors         {             get { throw new NotImplementedException(); }         }         #endregion         #region INotifyPropertyChanged Members         public event PropertyChangedEventHandler PropertyChanged;         #endregion ~~~ 另外定义一个新的数据成员,UserName ~~~         #region data memebers         private string _username;         public string UserName         {             get { return _username; }             set             {                 _username = value;             }         }         #endregion ~~~ 完成以上的客户端准备步骤,我们首先到Web服务器端创建一个Silverlight enabled WCF Service, ValidationService。 这里我不再演示具体的创建步骤,如果不会创建的,请参考这里:[图文详解Silverlight访问MSSQL数据库](http://www.silverlightchina.net/html/tips/2009/1229/503.html) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd0a791.jpg) 在服务端,我们创建简单的验证代码,如下 ~~~     [ServiceContract(Namespace = "")]     [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]     public class ValidationService     {         [OperationContract]         public bool ValidationUserName(string username)         {             if (username == "jv9")                 return true;             else                 return false;         }     } ~~~ 创建完毕后,编译SilverlightValidationDemo.Web项目,然后回到Silverlight客户端,添加一个新的服务引用, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd1da2f.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd2e90f.jpg) 搜索到刚创建的ValidationService服务,添加到客户端,Visual Studio 2010会自动创建客户端配置文件ServiceReferences.ClientConfig, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd40cf3.jpg) 到这里一个WCF服务已经创建成功,下面,修改Staff类, 之前,我们已经创建了新的数据成员UserName,另外执行INotifyDataErrorInfo接口,自动生成ErrorsChanged事件,GetErrors方法和HasErrors属性。 首先,需要对GetErrors方法进行重构,创建全局变量_validationErrors,承载验证错误信息集合. ~~~ private Dictionary<string, ObservableCollection<string>> _validationErrors;         public System.Collections.IEnumerable GetErrors(string propertyName)         {             if (!string.IsNullOrEmpty(propertyName))             {                 if (_validationErrors.ContainsKey(propertyName))                     return _validationErrors[propertyName];                 else                     return null;             }             else                 return null;         } ~~~ 然后,对HasErrors属性进行重构,,判断是否有验证错误, ~~~          public bool HasErrors         {             get              {                 foreach (string key in _validationErrors.Keys)                 {                     if (_validationErrors[key].Count > 0)                         return true;                 }                 return false;             }         } ~~~ 创建构造函数,和初始化错误集合, ~~~         public Staff()         {             _validationErrors = new Dictionary<string, ObservableCollection<string>>();             GenerateErrorsCollection("UserName");         }         #endregion         #region private methods         private void GenerateErrorsCollection(string propertyName)         {             if (!_validationErrors.ContainsKey(propertyName))             {                 _validationErrors.Add(propertyName, new ObservableCollection<string>());             }         } ~~~ 添加调用服务客户端代码, ~~~         private void ValidateUserNameandPasswordAsync(string username)         {             var client = new ValidationService.ValidationServiceClient();             client.ValidationUserNameCompleted += (o, e) =>             {                 _validationErrors["UserName"].Clear();                 if (e.Result)                 {                     _username = username;                     NotifyPropertyChanged("UserName");                 }                 else                 {                     _validationErrors["UserName"].Add("服务器端返回错误,用户名必须是jv9");                 }                 if (ErrorsChanged != null)                 {                     ErrorsChanged(this, new DataErrorsChangedEventArgs("UserName"));                 }             };             client.ValidationUserNameAsync(username);         } ~~~ 在数据成员中,添加验证方法调用, ~~~         #region data memebers         private string _username;         public string UserName         {             get { return _username; }             set             {                 _username = value;                 ValidateUserNameandPasswordAsync(value);             }         }         #endregion ~~~ 其运行效果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cd50990.jpg) 在每次修改用户框内容后,应用会自动向WCF服务请求验证,如果验证失败,则弹出验证错误信息,反之,则继续。 INotifyPropertyChanged接口,相比前面介绍的几个验证机制,其复杂程度较高,需要开发人员设计部分代码,但是其异步服务器端数据验证功能和单一属性添加多个错误信息功能,是Silverlight企业级项目中常用到的功能。在随后的项目中,我们会使用更多实例演示其强大功能。 今天就到这里了。 [源代码下载](http://www.silverlightchina.net/uploads/soft/100914/1-100914200150.rar) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)    
';

Validation数据验证DataAnnotation机制和调试技巧

最后更新于:2022-04-01 14:20:56

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在学习了[Silverlight Validation数据验证基础属性和事件](http://www.cnblogs.com/jv9/archive/2010/09/09/1821891.html)后,大家对Silverlight数据验证应该有了一个简单明了的认识。今天,我将继续介绍另外一种Silverlight的Validation验证机制,DataAnnotation。 在文章开始前,我想首先介绍一下Visual Studio中如何调试Silverlight的Validation代码。 Visual Studio 2010调试Silverlight Validation设置技巧* 相信大家在运行上一篇的代码时会发现,在异常出现时,Visual Studio会自动中断和获取当前异常错误信息,这为调试带来了一些不便。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc33865.jpg) 针对以上问题,我们可以在Visual Studio中进行简单设置,暂时取消在Debug模式下对异常的捕获,方法如下: 首先到Debug菜单,选择Exceptions菜单,也可以使用“Ctrl+Alt+E”,激活Exception窗口 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc42b33.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc56021.jpg) 点击“Find”查找以下选项, System.Exception,将其后面的CheckBox取消选中, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc6e9e4.jpg) 这样就实现了当数据验证时,Visual Studio不再捕获异常错误。 对于本篇,我们将使用DataAnnotation验证机制,该验证机制与[上一篇](http://www.cnblogs.com/jv9/archive/2010/09/09/1821891.html)略有不同,所以,如果要实现Visual Studio忽略捕获异常,要另外在Exception窗口搜索“System.ComponentModel.DataAnnotations.ValidationException",同样将其后面的CheckBox取消选中。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc7e667.jpg) Visual Studio 2008和Silverlight 3开发环境中,默认情况下Exception没有System.ComponentModel.DataAnnotations.ValidationException选项,开发人员可以自行添加一个新的异常即可,点击“Add”按钮, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc8e569.jpg) 在完成以上的操作后,再次执行Silverlight应用调试Validation时,Visual Studio不再出现异常捕获,相对方便很多。 [Silverlight DataAnnotation](http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx)验证机制 **验证Metadata属性** Silverlight的DataAnnotation验证机制是Silverlight 3发布WCF RIA Services测试版是推出的客户端验证机制,对于DataAnnotation的翻译,可以理解为“数据元素注释”验证法。该验证机制,使用了System.ComponentModel.DataAnnotations命名空间中的属性类,通过对DataMember数据成员设置Metadata元数据属性,对其验证值进行判断是否符合当前属性条件,以达到Validation的效果。该验证机制,多数运用于WCF RIA Services应用中. ~~~           private string _email;           [Required(ErrorMessage = "必填选项")]           public string email           {               get { return _email; }               set                {                   _email = value;                }          } ~~~ 从上面代码可以看到属性上面的注释 [Required(ErrorMessage = "必填选项")],该注释就是DataAnnotations类中的固有属性,其结果是判断该控件内容是否为空,如果是,则弹出异常。目前常用的DataAnnotation属性如下列表: <table class="MsoTableGrid" style="border-collapse: collapse; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt;" border="1" cellspacing="0" cellpadding="0"><tbody><tr style="height: 29.55pt; mso-yfti-irow: 0; mso-yfti-firstrow: yes;"><td style="padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; border: black 1pt solid;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">属性名称</span><span lang="EN-US"/></strong></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: black 1pt solid; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1;" width="326"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">描述</span><span lang="EN-US"/></strong></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 1;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">Required</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性为必需参数,不能为空</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 2;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">StringLength</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该字符串有长度限制,可以限制最小或最大长度</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 3;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">Range</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性值范围,通常被用在数值型和日期型</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 4;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">RegularExpression</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性将根据提供的正则表达式进行对比验证</span><span lang="EN-US"/></p></td></tr><tr style="height: 29.55pt; mso-yfti-irow: 5; mso-yfti-lastrow: yes;"><td style="border-bottom: black 1pt solid; border-left: black 1pt solid; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 92.8pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1;" width="124"><p class="MsoNormal" style="text-align: center; line-height: normal; margin: 0cm 0cm 0pt;" align="center"><span lang="EN-US"><span style="font-family: Calibri;">CustomValidation</span></span></p></td><td style="border-bottom: black 1pt solid; border-left: #f0f0f0; padding-bottom: 0cm; background-color: transparent; padding-left: 5.4pt; width: 244.7pt; padding-right: 5.4pt; height: 29.55pt; border-top: #f0f0f0; border-right: black 1pt solid; padding-top: 0cm; mso-border-alt: solid black .5pt; mso-border-themecolor: text1; mso-border-left-alt: solid black .5pt; mso-border-left-themecolor: text1; mso-border-top-alt: solid black .5pt; mso-border-top-themecolor: text1; mso-border-bottom-themecolor: text1; mso-border-right-themecolor: text1;" width="326"><p class="MsoNormal" style="line-height: normal; margin: 0cm 0cm 0pt;"><span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;" lang="ZH-CN">标识该属性将按照用户提供的自定义验证方法,进行数值验证</span><span lang="EN-US"/></p></td></tr></tbody></table> 在随后的实例中,我们将一一演示这些属性的使用方法。 **ValidationContext和Validator类** 阅读过上一篇Silverlight Validation基础的朋友应该知道,Silverlight的数据验证,可以在数据成员的Setter中设置条件验证,根据其验证结果判断是否符合验证。例如: ~~~           private int _age;           public int Age           {               get { return _age; }               set               {                   if (value > 100 || value < 0)                   {                       throw new Exception("请输入年龄值在0 - 100之间.");                  }                  _age = value;              }          } ~~~ 在set中,判断年龄值是否超过100岁或者低于0岁,如果不符合条件,则抛出异常,该异常将被Validation机制捕获,并显示到UI。 而Silverlight的DataAnnotation机制,与上面验证方法不同。Silverlight的DataAnnotation验证机制,在添加验证属性后,不需要在Setter中进行验证判断,仅需要在Setter中激活该验证属性即可,而要实现激活验证,则需要使用ValidationContext和Validator类。为了更好的理解Silverlight DataAnnotation验证机制,我们来对这两个类进行简单的讲解, 首先说说[Validator类](http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validator.aspx),该类是一个静态类,主要用来当数据成员被指定验证元数据属性时,验证对象,属性和方法。简单的理解就是包含了各种具体验证方法的类。例如上文代码,我们使用了Require验证属性,Validator类将会根据该验证属性执行对应的验证方法,对目标值进行判断。在该类中,包含ValidateProperty方法和TryValidateProperty方法,可以分别对当前属性进行验证操作。 而[ValiationContext类](http://msdn.microsoft.com/en-us/library/dd382177.aspx),该类是对当前执行的数据验证提供上下文描述的。简单的理解,也就是为验证提供数据传输,属性标识等任务。 我们对email属性,进行简单的修改,添加以上两个类,让该属性Silverlight的DataAnnotation机制生效。 ~~~           private string _email;           [Required(ErrorMessage = "必填选项")]           public string email           {               get { return _email; }               set                {                   var tmpValidator = new ValidationContext(this, null, null);                   tmpValidator.MemberName = "email";                  Validator.ValidateProperty(value, tmpValidator);                  _email = value;               }          } ~~~ 在上文代码中,我们定义一个ValidationContext实例,该实例中包含了需要验证对象的引用,并且,我们定义了验证对象的MemberName,通过调用Validator.ValidateProperty静态方法,检查目标数据是否符合当前验证属性,如果返回False,则抛出一个ValidationException。 上面代码也可简写为: ~~~ Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "email" }); ~~~ 当运行实例后,输入空格在邮件文本框中,Silverlight的DataAnnotation验证机制将被激活,生成如下效果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc9dd9d.jpg) 在理解了上面的Silverlight的DataAnnotation验证机制的基本类和属性后,我们可以做几个简单的实例,来加深理解。 1. StringLength,定义Password密码框最大可输入6个字符, ~~~              <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="密   码: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtPassword" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=password, Mode=TwoWay,ValidatesOnExceptions=True, NotifyOnValidationError=True}" />              </StackPanel> ~~~ ~~~           private string _password;           [StringLength(6, ErrorMessage="密码不能超过6个字符")]           public string password           {               get { return _password; }               set                {                   Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "password" });                   _password = value;               }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ccaef0b.jpg) 2. Range,我们使用Range属性设置Age年龄的有效范围, ~~~  <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="年   龄: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtAge" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=Age, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}" />              </StackPanel> ~~~ ~~~           private int _age;           [Range(0, 100, ErrorMessage = "请输入年龄值在0 - 100之间")]           public int Age           {               get { return _age; }               set               {                   Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Age" });                  _age = value;              }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ccc484a.jpg) 3. RegularExpression,我们使用正则表达式属性,验证邮件输入框。 ~~~  <StackPanel Orientation="Horizontal" Margin="5">                  <TextBlock Text="邮   件: " VerticalAlignment="Center"/>                  <TextBox x:Name="txtEmail" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=email, Mode=TwoWay, ValidatesOnNotifyDataErrors=False, NotifyOnValidationError=True, ValidatesOnExceptions=True}" />              </StackPanel> ~~~ ~~~           private string _email;           [Required(ErrorMessage = "必填选项")]           [RegularExpression(@"^([0-9a-zA-Z]([-./w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-/w]*[0-9a-zA-Z]/.)+[a-zA-Z]{2,9})$",ErrorMessage="请输入正确的Email格式")]           public string email           {               get { return _email; }               set                {                   var tmpValidator = new ValidationContext(this, null, null);                  tmpValidator.MemberName = "email";                  Validator.ValidateProperty(value, tmpValidator);                  _email = value;               }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ccd38a6.jpg) 4. 自定义验证方法的应用 我们创建一个简单的自定义验证方法,验证用户名是否为jv9. 首先创建自定义验证类,CustomizeValidation,在类中添加引用,using System.ComponentModel.DataAnnotations; 然后继承ValidationAttribute类,使其预定义该类为自定义验证属性, 完成上面的设置后,即可创建自定义验证方法。 ~~~      public class CustomizeValidation : ValidationAttribute      {          protected override ValidationResult IsValid(object value, ValidationContext validationContext)          {              String checkName = value.ToString();                return checkName == "jv9" ? ValidationResult.Success : new ValidationResult("请使用指定用户名");          }      } ~~~ 在Name属性中,进行调用, ~~~           private string _name;           [CustomizeValidation]           public string Name           {               get { return _name; }               set                {                   Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Name" });                   if (string.IsNullOrEmpty(value))                  {                      throw new Exception("用户名不能为空.");                  }                  _name = value;               }          } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cce6577.jpg) 对于Silverlight的DataAnnotation验证机制,相比其他验证机制使用起来较为简单,但是其本身具有一定局限性。特别是当数据成员来自服务器端,会因为类库无法共享使用造成无法正常验证。前文曾提及,该验证机制多数用在WCF RIA Services,因为WCF RIA应用提供的数据层,可生成对应客户端代码,即可实现在客户端的DataAnnotation验证。在随后的实例中,我将演示一套WCF RIA服务下的验证实例。 今天讲到这里,希望大家能够有所收获。 [源代码下载](http://files.cnblogs.com/jv9/SilverlightValidationDemo.rar) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)
';

Validation数据验证基础属性和事件

最后更新于:2022-04-01 14:20:54

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) [上篇](http://www.cnblogs.com/jv9/admin/Silverlight实例教程%20-%20Validation数据验证开篇)介绍了Silverlight的Validation数据验证的好处和概述,其中了解到Silverlight数据验证方法可以被抽象为语法验证和语义验证,其中前者是通过数据类型定义对比验证,而后者是通过当前输入数据根据特定数据限制代码进行验证。本篇将在以上抽象方法的基础上结合实例,介绍Silverlight Validation数据验证类中常用属性和方法。 本篇,我们将创建一个新的实例项目,SilverlightValidationDemo ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cb339de.jpg) 在MainPage,创建简单的用户交互界面: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cb4818f.jpg) 另外需要准备一个简单的数据成员类,方便随后的演示, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cb55d3e.jpg) 在实例演示前,我们仍旧需要先学习一下Silverlight的Validation数据验证框架基础属性和事件, 首先需要了解的是 [BindingValidationError](http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.bindingvalidationerror(v=VS.95).aspx)事件 该事件是一个路由事件,当数据验证错误出现时,将绑定该错误到数据源;也可以简单的理解为绑定错误到数据源的一个行为。该事件可在控件本身调用,也可在其父控件中调用。例如,在TextBox中,可以声明调用BindingValidationError,或者可以该TextBox的父容器控件Grid,StackPanel中调用BindingValidationError事件。这里需要注意的是,如果在Silverlight的MVVM设计模式下,仅在被验证的控件本身激活BindingValidationError事件,才能正常的被UI捕获到错误信息,不支持在父控件中对BindingValidationError事件进行调用。 为了保证Validation的灵活性,微软同时提供了相关属性,来控制BindingValidationError事件的调用。NotifyOnValidationError和ValidatesOnExceptions属性。 [NotifyOnValidationError](http://msdn.microsoft.com/en-us/library/system.windows.data.binding.notifyonvalidationerror(VS.95).aspx)属性 该属性的功能,是当验证错误出现时是否激活BindingValidationError事件;该属性是Silverlight独有的验证属性之一,经常和ValidatesOnExceptions属性配合使用。 [ValidatesOnExceptions](http://msdn.microsoft.com/en-us/library/system.windows.data.binding.validatesonexceptions(v=VS.95).aspx)属性 该属性的功能,数据绑定引擎是否捕获显示异常错误作为验证错误。简单的理解,在控件绑定数据时,出现数据源异常抛出,或者数据类型转换时异常抛出,是否作为Validation验证显示在客户端。如果是True,则会按照Validation传统的处理方式,弹出一个红色说明标签,内容是异常错误信息,反之,则不捕获异常作为Validation。 对于Silverlight开发新手而言,初次看到以上概念,会有混淆,请继续看下面实例,结合实例来理解以上的属性和事件使用方法。 首先,我们在MainPage中,将我们起初定义的User类添加作为一个静态数据源, ~~~ xmlns:local="clr-namespace:SilverlightValidationDemo" ~~~ ~~~ <UserControl.Resources>          <local:User x:Key="UserDataContext"/>  </UserControl.Resources> ~~~ 对于控件数据绑定,在Visual Studio中可以通过视图设定,也可以直接敲入代码设定,这里,我们使用视图的方法,减少代码输入量, 在MainPage中,选中txtUserName文本框,右键选择属性, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cb69dba.jpg) 在属性框中,设置绑定数据源, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cb7ad14.jpg) 选择Common - DataContext,然后选择“Apply Data Binding.." 选择数据源 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cb8cd5e.jpg) 这里,数据源可以选择外部数据源,也可以选择Element绑定源,我们则使用StaticResource静态数据源,也就是我们刚才创建的UserDataContext, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cba06ca.jpg) 选中后,绑定数据源已经完成,则需要设置控件绑定字段设置,选择Common - Text属性, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cbb8da0.jpg) 然后选择 Apply Data Binding...,进入后可以看到,数据源,已经绑定为“DataContext - User”,而数据源中的成员名称已经被自动列出, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cbcc638.jpg) 我们需要指定绑定成员名称, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cbdb36f.jpg) 然后,选择“Options”,在选项中,选中“NotifyOnValidationError”和“ValidatesOnExceptions”, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cbeae71.jpg) 这样控件绑定设置已经完成了,这时,可以切换到Xaml代码界面查看一下当前txtUserName的代码可以发现,Visual Studio 2010已经自动生成了绑定代码,如下: ~~~ <TextBox x:Name="txtUserName" Width="200" DataContext="{Binding Source={StaticResource UserDataContext}}" Text="{Binding Path=Name, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" /> ~~~ 现在,我们在name数据成员属性中,添加简单的判断代码: ~~~   private string _name;   public string Name   {               get { return _name; }               set                {                   if (string.IsNullOrEmpty(value))                   {                       throw new Exception("用户名不能为空.");                  }                  _name = value;               }  } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc0904a.jpg) 这样一个简单的Validation数据验证功能就完成了。 大家可以试着将ValidatesOnExceptions=True代码设为False,看看是否还能捕获异常验证? 下面,看看BindingValidationError事件和NotifyOnValidationError属性的应用, 我们添加一个TextBlock控件,用来显示验证异常信息, ~~~ <StackPanel Orientation="Horizontal" >         <TextBlock x:Name="tbMessage" Margin="5" Foreground="Red"/> </StackPanel> ~~~ 在MainPage中的LayoutRoot布局控件中,添加BindingValidationError事件, ~~~ <Grid x:Name="LayoutRoot" Background="White" BindingValidationError="LayoutRoot_BindingValidationError"> ~~~ 后台定义: ~~~   private void LayoutRoot_BindingValidationError(object sender, ValidationErrorEventArgs e)   {               if (e.Action == ValidationErrorEventAction.Added)               {                   (e.OriginalSource as Control).Background = new SolidColorBrush(Colors.Yellow);                   tbMessage.Text= e.Error.Exception.Message;               }               if (e.Action == ValidationErrorEventAction.Removed)              {                  (e.OriginalSource as Control).Background = new SolidColorBrush(Colors.White);                  tbMessage.Text = "";              }  } ~~~ 在验证异常出现时,由于NotifyOnValidationError属性设置为True,所以,会执行BindingValidationError事件, 其中tbMessage会显示验证错误信息,而验证控件样式也会有改变。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cc1d35e.jpg) 大家可以试着将NotifyOnValidationError属性设置为False,会发现BindingValidationError事件将不再执行。 今天,就讲到这里了。本篇讲述的两个属性和一个事件,是Silverlight的Validation最基础的知识点,在随后的文章中会频繁出现,希望大家能够认真理解。 [源代码下载](http://www.silverlightchina.net/uploads/soft/100908/1-100ZQ44358.rar) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)  
';

Validation数据验证开篇

最后更新于:2022-04-01 14:20:52

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 说起来Validation验证功能,相信大家都不陌生,在应用中,当需要用户交互输入时,开发人员都会加入一些验证代码,这样可以有效的避免应用异常出现,也可以使应用的错误提示信息清晰明了的显示在客户端,有利于异常定位,同时也提高用户体验。特别是在商业应用项目中,使用Validation功能,可以在数据存入存储设备前,进行格式,以及内容的校验,这样也提高了数据存储的安全性。 下面的ASP.NET的验证控件演示,是传统Web应用中最常见的验证效果,其中包括Required Field Validator,Range Validator等验证控件, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ca7c537.jpg)  Ajax Validation: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ca91ceb.jpg) 而Silverlight同样提供类似于ASP.NET验证控件的支持,在[Silverlight Toolkit开源项目](http://silverlight.codeplex.com/)中,包含Data Input的Validation演示, 简单数据绑定验证, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67caa19b1.jpg) 下图为ValidationSummary控件演示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cab78bd.jpg) 为了帮助大家学习和掌握Silverlight的Validation功能,随后的几篇,我将详细介绍一下Silverlight的Validation功能,并将结合一些实例演示帮助大家理解Validation验证功能。 本系列应用开发环境是: Windows 7 Ultimate 英文版 Visual Studio 2010 Premium 英文版 Expression Blend 4 Premium 英文版 Silverlight 4 **Validation验证概述** Validation,是验证,校验的意思,通常发生在用户输入数据后,进行验证判断,以确认用户输入正确信息。在验证的方法中,我们可以简单的从两个验证类型理解Validation, 1. 语法验证,该验证类型是通过成员的数据类型定义对比验证当前输入数据类型得出的验证结果; 例如,定义一个int类型,而赋值是string时,则会返回错误异常,验证控件,将获取该异常信息反馈到客户端; ~~~ public int Zip {get;set} ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67caca371.jpg) 语法验证经常发生在数据改变之前,其表现方式会在UI中体现; 2. 语义验证,该验证类型是将当前输入数据根据特定数据限制代码进行验证; 例如:指定某TextBox为必须输入,或者限定某TextBox内容长度,或者使用正则表达式控制其输入内容,最典型的例子是对电子邮件地址的验证: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67caf1c79.jpg) 语义验证通常会发生在数据改变之后,其表现方式可以由开发人员控制,不一定会在UI中体现; 一个简单的数据绑定,异常捕获验证时序图,本篇,不计划讲解该图,我将在随后的实例中,解释该验证原理。  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67cb0f8b6.jpg) 今天暂时介绍到这里,随后几篇将结合具体的Validation类和实例,讲解Silverlight Validation应用。 欢迎加我的微博在线交流: [http://t.sina.com.cn/edmonton](http://t.sina.com.cn/edmonton) 同时欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)    
';

Out of Browser在线更新和Silent安装

最后更新于:2022-04-01 14:20:50

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 通过前几篇的学习和实践,相信大家可以很轻松的创建个性化Silverlight Out of Browser应用。上周,在[银光中国网论坛](http://bbs.silverlightchina.net/)有人问到对于Silverlight Out of Browser应用,如何进行在线更新?这篇将针对该问题,介绍一下Silverlight的Out of Browser应用如何进行在线更新的,另外,我们将介绍Silverlight 4中提供的一个新的Out of Browser应用安装方式。 首先说说Silverlight Out of Browser应用在线更新 在本系列[开篇](http://www.cnblogs.com/jv9/archive/2010/07/08/1773276.html)的时候,我们已经介绍,Silverlight Out of Browser和Silverlight Web应用有一些不同,Silverlight Web当更新了服务器端的XAP文件后,用户在重新载入时,会自动更新XAP文件到本地临时目录。而Silverlight Out of Browser应用的自动更新是通过调用[CheckAndDownloadUpdateAsync](http://msdn.microsoft.com/en-us/library/system.windows.application.checkanddownloadupdateasync(v=VS.95).aspx)方法和[Application.CheckAndDownloadUpdateCompleted](http://msdn.microsoft.com/en-us/library/system.windows.application.checkanddownloadupdatecompleted(v=VS.95).aspx)实现的,在判断[UpdateAvailable](http://msdn.microsoft.com/en-us/library/system.windows.checkanddownloadupdatecompletedeventargs.updateavailable(v=VS.95).aspx)属性为True时,说明一个新版本已经被发现和成功下载,相反则是False。如果在检测中发现异常,则可以通过[Error](http://msdn.microsoft.com/en-us/library/system.windows.checkanddownloadupdatecompletedeventargs.error(v=VS.95).aspx)属性查看异常实例信息。 按照常规方法,我们都会在应用启动时进行更新检测,所以,我们需要将代码添加到App.xaml的构造函数中, 首先创建OnCheckAndDownloadUpdateCompleted检测是否有新版本允许下载, ~~~   private void OnCheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)   {               if (e.UpdateAvailable && e.Error == null)               {                   MessageBox.Show("应用新版本已经下载成功,将在下次启动时生效。");               }               else if (e.Error != null)               {                   MessageBox.Show("在检测应用更新时, 在"                                + "出现以下错误信息:"                                + Environment.NewLine                                + Environment.NewLine                                + e.Error.Message);              }  } ~~~ 然后,添加声明在App的构造函数中,使其在安装时进行版本更新检查, ~~~   public App()   {               if (App.Current.InstallState == InstallState.Installed)               {                   App.Current.CheckAndDownloadUpdateCompleted += OnCheckAndDownloadUpdateCompleted;                   App.Current.CheckAndDownloadUpdateAsync();               }               this.Startup += this.Application_Startup;              this.Exit += this.Application_Exit;              this.UnhandledException += this.Application_UnhandledException;              InitializeComponent(); } ~~~ 这样,在Silverlight OOB应用启动时,将检测是否是否有新版本下载,如果有则会自动更新,在下次启动应用时生效。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ca62407.jpg) 这里需要说明的是,Silverlight Out of Browser的自动更新,需要在信任应用(Trusted Application)下才能正常执行,否则将返回权限异常错误。 Silverlight Out of Browser的Silent安装模式 我们在[Silverlight实例教程 - Out of Browser配置,安装和卸载](http://www.cnblogs.com/jv9/archive/2010/07/10/1774687.html)中讨论过Silverlight OOB应用安装的两种方式,这里,我们将介绍Silverlight 4中新推出的一种安装方式,叫做Silent安装。这种安装方式是使用命令的方式安装Silverlight OOB应用到本地,该方式不会在客户端显示任何窗口提示信息,悄然的把应用安装到本地。通常,一些开发人员习惯该安装方式应用于一个BAT批处理文件中,让非专业用户简单的安装和使用其应用程序。其实这种安装方式,也就是将XAP文件安装到本地。 大家还记得[开篇](http://www.cnblogs.com/jv9/archive/2010/07/08/1773276.html)时介绍sllauncher.exe命令么"C:/Program Files (x86)/Microsoft Silverlight/sllauncher.exe" 1359404922.localhost,我们使用sllauncher命令执行本地XAP文件,当我们添加/install参数时,即可实现silent安装OOB应用。 先看看具体的silent安装命令格式: "C:/Program Files/Microsoft Silverlight/sllauncher.exe"   /install:"C:/SilverlightOOBDemo/SilverlightOOBDemo.xap"   /origin:http://localhost:29162/ClientBin/SilverlightOOBDemo.xap  /shortcut:desktop+startmenu   /overwrite    从上面的命令中可以看出sllauncher添加部分参数后,实现不同的功能操作,例如 /**install**:“XAP文件目的路径”,这个参数是允许开发人员自定义XAP文件安装路径,可以是本地磁盘,也可以是网络路径。这个参数是silent安装模式必需的参数。 /**origin**:"XAP文件源路径",这个参数是设置XAP文件的源URL,其目的是为了自动更新而设。作为官方推荐设置该参数,保证其应用自动更新。 /**shortcut**:desktop+startmenu,从字面意思就可以看出,这个参数是创建应用快捷方式的,desktop+startmenu为在桌面和开始菜单都创建该应用快捷方式,如果只想创建桌面快捷方式,使用/shortcut:desktop即可,创建开始菜单快捷方式与之同理。 /**overwrite**,这个选项是确认当前安装XAP文件是否覆盖已经安装过的XAP文件,通常来说,我们都会设置覆盖,这样保持应用为最新版本。 根据以上解释,可以对照看出上面silent安装命令的意思,运行sllauncher,安装SilverlightOOBDemo.xap到本地,源更新地址为[http://localhost:29162/ClientBin/SilverlightOOBDemo.xap](http://localhost:29162/ClientBin/SilverlightOOBDemo.xap),创建桌面和开始菜单快捷方式,并且覆盖原有版本。 另外我们再介绍两个常用sllauncher命令参数: /**emulate**:“XAP文件目的路径”,该命令参数允许安装OOB应用后,自动运行该应用,就像现在很多软件自带的autorun功能相似。 使用方法: "C:/Program Files/Microsoft Silverlight/sllauncher.exe"   /emulate:"C:/SilverlightOOBDemo/SilverlightOOBDemo.xap"   /origin:http://localhost:29162/ClientBin/SilverlightOOBDemo.xap  /overwrite    /**uninstall**,该命令参数允许开发人员通过命令的方式卸载Silverlight OOB应用。其使用方法: "C:/Program Files/Microsoft Silverlight/sllauncher.exe"   /uninstall /origin:http://localhost:29162/ClientBin/SilverlightOOBDemo.xap  看到这里,我想大家应该有一些明白了,无论是安装还是运行Silverlight OOB应用都和sllauncher命令有关, 安装时,使用/install参数, 运行时,使用默认"C:/Program Files (x86)/Microsoft Silverlight/sllauncher.exe" 1359404922.localhost, 卸载时,使用/uninstall参数。 这个就是Silverlight 4中Out of Browser应用特性之一,Silent Install。 写到这里,[Silverlight 4 Out of Browser实例系列](http://www.cnblogs.com/jv9/archive/2010/08/03/1791632.html)也应该结束了,在该系列中,我们结合着实际例程学习了Silverlight Out of Browser的基础知识以及开发技巧。 在以后的时间里,希望大家能够勤于动手,多实践,开发出更多个性化的Silverlight Out of Browser应用。 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)  
';

Out of Browser与COM互操作实例

最后更新于:2022-04-01 14:20:47

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在前面已经介绍了Silverlight的[Out of Browser模式与COM的基本操作](http://www.cnblogs.com/jv9/archive/2010/07/23/1783379.html)以及[与Office COM的交互](http://www.cnblogs.com/jv9/archive/2010/07/24/1784102.html)。这篇我们将介绍更多Silverlight Out of Brwoser的COM实例。 我们将继续使用过去的SilverlightOOBDemo项目进行简单扩展。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c95a9ed.jpg) 实例1:演示Silverlight与DOS的交互,对于Windows API熟悉的朋友应该了解,使用[WShell](http://msdn.microsoft.com/en-us/library/ahcz2kh6(VS.85).aspx)可以运行任何Dos命令。 ~~~  private void dosBtn_Click(object sender, RoutedEventArgs e)  {              using (dynamic shell = AutomationFactory.CreateObject("WScript.Shell"))              {                  //shell.Run(@"cmd /k dir /w /p");                  shell.Run(@"cmd /k ping www.cnblogs.com -t");              } } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c96b23d.jpg) 实例2:使用[WShell API](http://msdn.microsoft.com/en-us/library/8c6yea83(VS.85).aspx)模拟用户输入实例。使用WShell的SendKeys可以模拟用户输入效果到应用程序中,并且可以模拟一些特殊键功能,例如,回车,Tab,Ctrl等按键。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c985548.jpg) 其中要实现模拟输入代码如下: ~~~  private void inputBtn_Click(object sender, RoutedEventArgs e)  {      using (dynamic shell = AutomationFactory.CreateObject("WScript.Shell"))      {          shell.Run(@"c:/windows/notepad.exe");          shell.SendKeys("my blog:{Enter}jv9.cnblogs.com");      }  } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c992e37.jpg) 实例3:Silverlight OOB应用读取注册表信息实例 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c9a50cd.jpg) 使用Shell.Application的[RegRead方法](http://msdn.microsoft.com/en-us/library/x05fawxd(VS.85).aspx)可以读取本地注册表键值,例如,读取“HKLM/Software/Microsoft/ASP.NET/RootVer”,.Net Framework的版本。 ~~~  private void regBtn_Click(object sender, RoutedEventArgs e)  {              using (dynamic WShell = AutomationFactory.CreateObject("WScript.Shell"))              {                  string reg = WShell.RegRead(@"HKLM/Software/Microsoft/ASP.NET/RootVer");                  MessageBox.Show(".Net Framework Root Version: " + reg);              } } ~~~ 读取结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c9b5a6b.jpg) 实例4:使用Shell.Application的[RegWrite方法](http://msdn.microsoft.com/en-us/library/yfdfhz1b(VS.85).aspx)可以对注册表进行写操作。这个实例将实现添加Silverlight Out of Browser应用到Windows启动项。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ca1a6c4.jpg) ~~~   private void regWriteBtn_Click(object sender, RoutedEventArgs e)   {               using (dynamic ShellApplication = AutomationFactory.CreateObject("Shell.Application"))               {                   dynamic commonPrograms = ShellApplication.NameSpace(11);                  string allUsersPath = commonPrograms.Self.Path;                  dynamic directory = ShellApplication.NameSpace(allUsersPath + @"/Programs");                   dynamic link = directory.ParseName(Deployment.Current.OutOfBrowserSettings.ShortName + ".lnk");                  string OOBLink = link.Path;                  using (dynamic WShell = AutomationFactory.CreateObject("WScript.Shell"))                  {                      WShell.RegWrite(@"HKLM/Software/Microsoft/Windows/CurrentVersion/Run/"                                                   + Deployment.Current.OutOfBrowserSettings.ShortName,                                                   OOBLink);                      MessageBox.Show("请重启你的机器,你的应用将被自动载入启动列表.");                  }             }  } ~~~ 当运行以上代码后,应用会将OOB应用快捷方式写入注册表HKLM/Software/Microsoft/Windows/CurrentVersion/Run/ 应用程序将在下次重启后,自动启动。 实例5:使用Windows 7 API实现锁定应用到Windows 7任务栏 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ca29112.jpg) 在Windows 7中使用Shell.Application类库允许遍历应用,检查Verbs进行应用锁定。 ~~~   private void pinBtn_Click(object sender, RoutedEventArgs e)   {               using (dynamic ShellApplication = AutomationFactory.CreateObject("Shell.Application"))               {                   dynamic commonPrograms = ShellApplication.NameSpace(23);                   string allUsersPath = commonPrograms.Self.Path;                  dynamic directory = ShellApplication.NameSpace(allUsersPath + @"/Accessories");                   dynamic link = directory.ParseName("Calculator.lnk");                  dynamic verbs = link.Verbs();                  for (int i = 0; i < verbs.Count(); i++)                  {                      dynamic verb = verbs.Item(i);                      if (verb.Name.Replace(@"&", string.Empty).ToLower() == "pin to taskbar")                      {                          verb.DoIt();                      }                  }              }  } ~~~ 当执行以上代码后,获取计算器应用快捷方式,然后执行“Pin to Taskbar”后,将应用锁定在Windows 7任务栏。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ca38de0.jpg) 实例6:Silverlight Out of Browser语音阅读实例 使用Windows自带的Speech API中的SAPI引擎SpVoice类可以实现语音阅读功能。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67ca498c5.jpg) ~~~  private void speechBtn_Click(object sender, RoutedEventArgs e)  {              using (dynamic ISpeechVoice = AutomationFactory.CreateObject("SAPI.SpVoice"))              {                  ISpeechVoice.Volume = 100;                  ISpeechVoice.Speak("<rate speed=/"0/"><pitch middle=/"0/">Hello everyone! Welcome to my blog,http://jv9.cnblogs.com");              }  } ~~~ 当运行以上代码后,会听到以上阅读内容。 对于Silverlight Out of Browser的COM应用有一款开源项目COM Toolkit,该控件在OOB模式下可以对本地数据库进行操作,[推荐大家参考学习](http://silverlightchina.net/html/works/2010/0808/1702.html)。 今天就写到这里了,希望能对大家有所帮助。 [源代码下载](http://www.silverlightchina.net/resource/code/SilverlightOOBDemo0808.rar) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)  
';

Out of Browser音乐播放器

最后更新于:2022-04-01 14:20:45

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c868925.jpg) 在[上一篇](http://www.cnblogs.com/jv9/archive/2010/07/27/1785689.html),我们了解了如何在Silverlight的Out of Browser模式下进行Debug调试,另外学习Silverlight OOB应用的一个新特性Notifications窗口。本篇,我们将结合以往的Out of Browser特性,创建一款新的Out of Browser实例, 音乐播放器。 该实例目的比较简单,实现音乐播放,实现音乐文件列表读取,实现音乐文件信息读取,另外音乐播放自动跳转等功能。 在实例开始前,我们仍旧需要了解一些基础知识。Silverlight对音频的支持是使用MediaElement类,该类使用方法非常简单,该类的详细解释,[请看MSDN](http://msdn.microsoft.com/en-us/library/system.windows.controls.mediaelement(VS.95).aspx) ~~~  <MediaElement       x:Name="media"       Source="xbox.wmv"       CurrentStateChanged="media_state_changed"       Width="300" Height="300"/> ~~~ 在了解了音频播放类的简单使用后,让我们先看看项目完成后的效果图, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c8809b6.jpg) 从上面效果图中可以看出整个实例项目UI分5个部分, 1. 音频控制部分,这部分是实例主要功能; 2. 音频文件信息部分,这部分是获取显示当前和下一首音乐文件信息; 3. 唱片图片信息,其实这部分也是属于音频文件信息,不过这里单独列出来,使用独立的类进行处理; 4. 音频文件列表,该列表是载入My Music目录中的音乐文件,并支持用户选择播放功能; 5. UI控制,该部分可以使播放器进入最小化状态。例如: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c898ed8.jpg) 下面我们开始分别解释以上几个部分的实例设计方法。 我们仍旧使用SilverlightOOBDemo项目,不过为了使代码更清晰易读,这次不再使用OutofBrowserMainPage作为OOB应用主界面,我们重新创建一个新的OOB应用界面OutofBrowserMusicPlayer。 为了修改启动页面为OutofBrowserMusicPlayer,为此,我们需要修改App.xaml中的启动页面代码: ~~~   private void Application_Startup(object sender, StartupEventArgs e)   {               if (!Application.Current.IsRunningOutOfBrowser)               {                   this.RootVisual = new MainPage();              }               else               {                   //this.RootVisual = new OutofBrowserMainPage();                  this.RootVisual = new OutofBrowserMusicPlayer();              } } ~~~ 根据实例需求,我们最主要的功能就是播放音乐,所以,我们第一步首先实现Out of Browser应用音频控制。 **1. 创建自定义音频控制控件;** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c8ab7da.jpg) 对于音频控制,这里我们使用了自定义控件控制音乐的播放。AudioControl.xaml控件, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c8c2576.jpg) 这里我仅贴上部分代码,大家可以在文章最后下载完整源代码。 ~~~   <Grid x:Name="LayoutRoot">           <Grid.ColumnDefinitions>               <ColumnDefinition Width="Auto" />               <ColumnDefinition Width="*" />               <ColumnDefinition Width="25" />               <ColumnDefinition Width="Auto" />               <ColumnDefinition Width="Auto" />           </Grid.ColumnDefinitions>           <Grid Grid.Column="0" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" x:Name="gridCol1">              <ToggleButton Cursor="Hand" Margin="0,0,0,0" x:Name="btnPlay" RenderTransformOrigin="0.5,0.5" Template="{StaticResource playControlTemplate}">                  <ToggleButton.RenderTransform>                      <TransformGroup>                          <ScaleTransform ScaleX="1" ScaleY="1"/>                          <SkewTransform/>                          <RotateTransform/>                          <TranslateTransform/>                      </TransformGroup>                  </ToggleButton.RenderTransform>              </ToggleButton>         </Grid>          <Grid Grid.Column="1" Margin="0,0,0,0" HorizontalAlignment="Stretch" x:Name="gridCol2" VerticalAlignment="Center">              <Grid.ColumnDefinitions>                  <ColumnDefinition Width="*" />                  <ColumnDefinition Width="40" />                  <ColumnDefinition Width="10" />                  <ColumnDefinition Width="40" />              </Grid.ColumnDefinitions>              <TextBlock x:Name="tbCurrentTime" Margin="0,1.5,0,0"  Height="12" FontFamily="Verdana" FontSize="10" Text="00:00" TextWrapping="Wrap" Foreground="#FFFFFFFF" FontStyle="Normal" HorizontalAlignment="Right" TextAlignment="Right" Grid.Column="1"/>              <TextBlock Margin="0,1.5,0,0"  Height="12" FontFamily="Verdana" FontSize="10" Text="/" TextWrapping="Wrap" Foreground="#FFFFFFFF" FontStyle="Normal" HorizontalAlignment="Center" TextAlignment="Right" Grid.Column="2"/>              <TextBlock x:Name="tbTotalTime" Margin="0,1.5,0,0"  Height="12" FontFamily="Verdana" FontSize="10" Text="00:00" TextWrapping="Wrap" Foreground="#FFFFFFFF" FontStyle="Normal" HorizontalAlignment="Left" TextAlignment="Right" Grid.Column="3"/>              <local:MediaSlider Margin="0,1.5,0,0" HorizontalAlignment="Stretch" Maximum="100" x:Name="sliderTimeline" Style="{StaticResource progressSliderStyle}" Grid.Column="0" Value="0" Visibility="Visible"/>          </Grid>          <Grid Grid.Column="2" Margin="4,0,4,0" HorizontalAlignment="Stretch" x:Name="gridCol3" VerticalAlignment="Center">              <local:Spinner Margin="0,0,0,0" x:Name="spinner" Width="17" Height="17" HorizontalAlignment="Center" VerticalAlignment="Center"/>          </Grid>          <Grid Grid.Column="3" Margin="0,10.30,0,10.30" HorizontalAlignment="Stretch" x:Name="gridCol4" Width="70" VerticalAlignment="Stretch" d:LayoutOverrides="Height">              <Grid Margin="0,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Center" Width="70">                  <Grid.ColumnDefinitions>                      <ColumnDefinition Width="Auto" />                      <ColumnDefinition Width="*" />                  </Grid.ColumnDefinitions>                  <ToggleButton HorizontalAlignment="Left" IsChecked="True" Margin="0,0,0,0" x:Name="btnSpeaker" Template="{StaticResource speakerControlTemplate}"/>                  <Slider Grid.Column="1" HorizontalAlignment="Stretch" Margin="3,0,0,0" VerticalAlignment="Center" Maximum="1" x:Name="sliderVolume" Style="{StaticResource volumeSliderStyle}" Background="#FF777777"/>              </Grid>          </Grid>          <Grid Grid.Column="4" Margin="0,10.3120002746582,4,10.3120002746582" HorizontalAlignment="Right" x:Name="gridCol5" VerticalAlignment="Stretch" d:LayoutOverrides="Height">              <ToggleButton Cursor="Hand" HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="btnFullScreen" Template="{StaticResource fullScreenControlTemplate}"/>          </Grid>      </Grid> ~~~ 从以上代码可以看到,在AudioControl中有两个自定义控件local:MediaSlider和local:Spinner。 MediaSlider: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c8d18eb.jpg) 其功能是控制音乐播放进度,支持拖拽前进或者后退音乐播放进度。其代码如下: ~~~    public class MediaSlider : Slider        {            public Thumb              horizontalThumb;            private FrameworkElement horizontalLeftTrack;            private FrameworkElement horizontalRightTrack;            private double oldValue = 0, newValue = 0, prevNewValue = 0;            public event RoutedPropertyChangedEventHandler<double> MyValueChanged;            public event RoutedPropertyChangedEventHandler<double> MyValueChangedInDrag;            private DispatcherTimer dragtimer = new DispatcherTimer();           private double dragTimeElapsed = 0;           private const short DragWaitThreshold = 200, DragWaitInterval = 100;           public Rectangle progressRect = null;           private bool dragSeekJustFired = false;          public MediaSlider()           {              this.ValueChanged += new RoutedPropertyChangedEventHandler<double>(CustomSlider_ValueChanged);              dragtimer.Interval = new TimeSpan(0, 0, 0, 0, DragWaitInterval);               dragtimer.Tick += new EventHandler(dragtimer_Tick);          }           void dragtimer_Tick(object sender, EventArgs e)          {               dragTimeElapsed += DragWaitInterval;               if (dragTimeElapsed >= DragWaitThreshold)               {                   RoutedPropertyChangedEventHandler<double> handler = MyValueChangedInDrag;                                      if ((handler != null) && (newValue != prevNewValue))                   {                       handler(this, new RoutedPropertyChangedEventArgs<double>(oldValue, newValue));                       dragSeekJustFired = true;                       prevNewValue = newValue;                   }                  dragTimeElapsed = 0;               }           }          void CustomSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)           {               oldValue = e.OldValue;               newValue = e.NewValue;              if (horizontalThumb.IsDragging)               {                   dragTimeElapsed = 0;                   dragtimer.Stop();                   dragtimer.Start();                   dragSeekJustFired = false;               }           }          public override void OnApplyTemplate()           {               base.OnApplyTemplate();               horizontalThumb = GetTemplateChild("HorizontalThumb") as Thumb;               horizontalLeftTrack = GetTemplateChild("LeftTrack") as FrameworkElement;               horizontalRightTrack = GetTemplateChild("RightTrack") as FrameworkElement;               progressRect = GetTemplateChild("Progress") as Rectangle;               if (horizontalLeftTrack != null) horizontalLeftTrack.MouseLeftButtonDown += new MouseButtonEventHandler(OnMoveThumbToMouse);               if (horizontalRightTrack != null) horizontalRightTrack.MouseLeftButtonDown += new MouseButtonEventHandler(OnMoveThumbToMouse);               horizontalThumb.DragCompleted += new DragCompletedEventHandler(DragCompleted);               progressRect.Width = this.Width;           }           public Storyboard ProgressStoryboard { get { return (GetTemplateChild("ProgressStoryboard") as Storyboard); } }           public Rectangle ProgressBar { get { return (GetTemplateChild("Progress") as Rectangle); } }           protected override Size ArrangeOverride(Size finalSize)          {               Size s = base.ArrangeOverride(finalSize);               if (double.IsNaN(horizontalThumb.Width) && (horizontalThumb.ActualWidth != 0))               {                   horizontalThumb.Width = horizontalThumb.ActualWidth;               }               if (double.IsNaN(horizontalThumb.Height) && (horizontalThumb.ActualHeight != 0))               {                   horizontalThumb.Height = horizontalThumb.ActualHeight;               }               if (double.IsNaN(horizontalThumb.Width)) horizontalThumb.Width = horizontalThumb.Height;               if (double.IsNaN(horizontalThumb.Height)) horizontalThumb.Height = horizontalThumb.Width;               return (s);           }                      private void OnMoveThumbToMouse(object sender, MouseButtonEventArgs e)           {              e.Handled = true;              Point p = e.GetPosition(this);              if (this.Orientation == Orientation.Horizontal)              {                  Value = (p.X - (horizontalThumb.ActualWidth / 2)) / (ActualWidth - horizontalThumb.ActualWidth) * Maximum;              }              RoutedPropertyChangedEventHandler<double> handler = MyValueChanged;              if (handler != null)              {                  handler(this, new RoutedPropertyChangedEventArgs<double>(oldValue, Value));              }          }          private void DragCompleted(object sender, DragCompletedEventArgs e)          {              dragtimer.Stop();              dragTimeElapsed = 0;              RoutedPropertyChangedEventHandler<double> handler = MyValueChanged;               if ((handler != null) && (!dragSeekJustFired))              {                  handler(this, new RoutedPropertyChangedEventArgs<double>(oldValue, this.Value));              }          }      } ~~~ 而Spinner控件,是一个载入标识,当音频载入时,会显示该控件。该控件为Path绘制的控件,这里不再贴出代码描述。 **2. 获取音频文件信息部分** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c8e37ab.jpg) 该部分我们同样也创建一个自定义控件来实现,TrackInfo.xaml,主要是负责在客户端显示音频文件的信息,而Silverlight没有相关API可以实现读取音频文件的标签信息,这里,我们需要引入一个微软开源类库TagLib。该类库的主要功能就是读取和修改音乐文件的标签信息。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c8f3622.jpg) 其调用方法非常简单: 1 // 获取标签 2 tags = TagLib.File.Create(MediaFile.ID); 3 // 设置标签属性 4 MediaFile.Artist = tags.Tag.FirstPerformer; 5 MediaFile.Title = tags.Tag.Title; 6 MediaFile.Album = tags.Tag.Album; 7 MediaFile.Genre = tags.Tag.FirstGenre; 当音乐标签信息获取成功后,即可将信息绑定到TrackInfo.DataContext。 **3. 唱片图片信息** 对于唱片的图片信息,这里需要读取Image从本地目录,当没有唱片图片时,则显示默认Music.png图片。这里需要注意的是,读取本地文件,需要OOB应用权限信任。 ~~~   public ImageSource AlbumArtStream   {               get               {                   BitmapImage image;                   if (string.IsNullOrEmpty(AlbumArtPath))                   {                       if (null == _default)                      {                          _default = new BitmapImage(new Uri("../Images/Music.png", UriKind.Relative));                      }                      image = _default;                  }                  else                  {                      FileStream stream = File.Open(AlbumArtPath, FileMode.Open, FileAccess.Read);                      image = new BitmapImage();                      image.SetSource(stream);                      stream.Close();                  }                  return image;              } } ~~~ **4. 获取音频文件列表** 从演示图片可以看出,我们的音频文件列表,是用了一个绑定了音乐播放文件信息的Datagrid。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c91061a.jpg) 其代码非常简单,创建两列,分别绑定歌手和歌曲名: ~~~   <data:DataGrid x:Name="playList"                          Grid.Row="1"                          Grid.Column="1"                          Grid.RowSpan="3"                          VerticalAlignment="Top"                          Margin="4"                          Height="296"                          Style="{StaticResource DataGridStyle}"                          AutoGenerateColumns="False"                         CanUserResizeColumns="True"                         CanUserSortColumns="False"                         SelectionChanged="playList_SelectionChanged">              <data:DataGrid.Columns>                  <data:DataGridTextColumn Header="歌手"                                           Binding="{Binding Artist}"                                           FontSize="12" />                  <data:DataGridTextColumn Header="歌名"                                           Binding="{Binding Title}"                                           FontSize="12"                                           Width="*" />              </data:DataGrid.Columns>  </data:DataGrid> ~~~ 而后台,在读取了My Music目录后,将数据集绑定到datagrid.ItemsSource就可以正常实现歌曲列表了。 ~~~   public static List<MediaFile> GetMediaFiles()   {               List<MediaFile> files = null; ;               MediaFile mf;               string path = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);               IEnumerable<string> list = Directory.EnumerateFiles(path, "*.mp3", SearchOption.AllDirectories);               TagLib.File tags;               files = GetCachedList(list);               if (null == files || files.Count == 0)              {                  files = new List<MediaFile>();                  foreach (string file in list)                  {                      mf = new MediaFile();                      mf.ID = file;                      mf.AlbumArtPath = GetAlbumArtPath(file);                      files.Add(mf);                  }                  for (int idx = 0; idx < files.Count; idx++)                  {                      mf = files[idx];                      tags = TagLib.File.Create(mf.ID);                      mf.Artist = tags.Tag.FirstPerformer;                      mf.Title = tags.Tag.Title;                      mf.Album = tags.Tag.Album;                      mf.Genre = tags.Tag.FirstGenre;                  }                  SaveCachedList(files);              }              return files; } ~~~ 在绑定成功后,同时,我们支持用户选择指定音乐播放,使用Datagrid的SelectionChanged事件即可。 ~~~   private void playList_SelectionChanged(object sender, SelectionChangedEventArgs e)   {               DataGrid dg = (sender as DataGrid);               if (dg.SelectedIndex != _nowPlaying)               {                   if (dg.SelectedIndex != 0)                   {                       me.AutoPlay = true;                  }                  OpenAndPlay(dg.SelectedIndex);              }               } ~~~ **5. UI控制** 对于UI的控制,这里我们只是简单的实现了隐藏和显示音乐信息框的功能,其代码实现: ~~~           private void Minimize_Click(object sender, MouseButtonEventArgs e)           {               Window main = Application.Current.MainWindow;              if (!_min)               {                   main.Height = 40;                   rot.Angle = 0;               }              else              {                  main.Height = 340;                  rot.Angle = 180;             }              _min = !_min;          } ~~~ 上面是OOB音乐播放器5个部分的核心功能代码,这里,我想同时将[上一篇](http://www.cnblogs.com/jv9/archive/2010/07/27/1785689.html)讲到的Notifications窗口应用到实例中,我们可以仍旧使用NotificationControl文件,在其中对播放音乐Title进行绑定,即当音乐播放完毕后,即弹出消息提示播放下一首“XXX”音乐。效果如下图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c91d818.jpg) 根据上一篇介绍Notifications窗口的代码,我们简单进行修改,即可实现本篇实例需求: ~~~           NotificationWindow notifyWindow = null;           private void ShowToast()           {               notifyWindow = new NotificationWindow();               if (notifyWindow.Visibility == Visibility.Visible)                  notifyWindow.Close();              NotificationControl myNotify = new NotificationControl();              myNotify.DataContext = _playList[_nowPlaying];              notifyWindow.Width = 300;              notifyWindow.Height = 100;              notifyWindow.Content = myNotify;              notifyWindow.Show(10000);          } ~~~ 至此,一款基于Silverlight的Out of Browser模式的音乐播放器基本完成了。大家可以根据该实例添加更多自定义功能,例如添加互联网音乐播放功能,音乐搜索功能等,创建属于自己的Silverlight版酷我音乐盒。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c92e3bd.jpg) [本篇源代码下载](http://www.silverlightchina.net/resource/code/SilverlightOOBDemo0727.zip) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)
';

Out of Browser的Debug和Notifications窗口

最后更新于:2022-04-01 14:20:43

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c435fed.png) 熟悉Silverlight的朋友应该知道,Silverlight从1.0版本到现在的4.0版本,其功能性越来越强大,从下图我们可以看出,Silverlight的应用模型的一个转变过程,从Javascript到现在Trusted应用,我们目睹了Silverlight坎坷的演变过程,尽管现在仍旧存在不足之处,但是有了更多开发人员的支持和帮助,Silverlight一定会更好更强大。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c7c94bc.jpg) 在前几篇中,我们通过简单的实例详细介绍了Silverlight Out of Browser应用开发基础。为了下一篇的实例做准备,本篇,我们将补充介绍一些Silverlight Out of Browser应用开发知识点,  1. 回顾Silverlight Out of Browser存取本地目录API; 2. 学习Silverlight Out of Browser应用Debug调试; 3. 学习Silverlight Out of Browser的消息通知窗口API; **回顾Silverlight Out of Browser存取本地目录API**,还记得在前面的文章我们已经介绍,Silverlight提供有现成的API,允许应用在OOB模式下访问My...系列目录,API调用方法很简单,而OOB模式下文件访问,应用可以支持System.IO引用空间中的操作类,例如File类,Directory类,Environment类,等等。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c7dc65a.jpg) ~~~   private void AddMusicToList()           {                var path = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);                lsMyMusics.Items.Clear();                DirectoryInfo myDirectory = new DirectoryInfo(path);                foreach (FileInfo file in myDirectory.EnumerateFiles())                {                    lsMyMusics.Items.Add(file);                }           } ~~~ 在下文中,我们将用到Silverlight默认API,读取My Music目录的音乐文件作为默认播放目录。其代码与上相似。 **Silverlight Out of Browser应用的调试方法(Debug)** 在使用Silverlight开发应用时,Debug是最常用的Visual Studio工具之一。大家可能对Silverlight基于Web浏览器的调试方法并不陌生,终归ASP.NET应用开发调试已经为Silverlight打下了良好的基础。而对于Silverlight的OOB是否通常支持Debug呢?答案是肯定的。 在创建项目时,默认的设置,是支持基于浏览器的应用的Debug。如果需要OOB应用支持脱离浏览器进行Debug,需要按照以下几个步骤设置: 1. 首先需要设置Silverlight客户端应用为“开始项目”, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c7ea566.jpg) 2. 然后选择客户端应用“Properties”属性栏,设置“Start Action”中的“Installed out-of-browser application”, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c80deda.jpg) 3. 点击保存后,重新F5调试应用,即可发现,应用将直接作为OOB模式启动,不再进入Web浏览器中提示用户安装,这时就可以在代码中设置断点进行Debug了。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c822e93.jpg) 学习Silverlight Out of Browser的消息通知窗口API(Toast Notifications Windows) Toast Notifications Windows,又称为Silverlight消息通知窗口,是Silverlight 4的一个新特性,该窗口目前仅限于Out of Browser应用使用。该消息窗口主要是提供临时消息提示,在应用中可以起到让用户注意警示的作用。现在很多Windows应用都喜欢使用该窗口模式显示广告,更新提示等功能。 Silverlight的Notifications Windows目前有以下限制: 1. 窗口最大尺寸限制,最大仅支持宽400,高100的提示窗口; 2. 目前不支持Transparency窗口特效,WPF可以支持; 3. 为了区别其他窗口应用,Notifications Windows无窗口边框; 在明白以上限制后,使用Silverlight API很轻松就能创建一个Toast Notifications窗口。其方法如下: 首先,在SilverlightOOBDemo中创建一个NotificationControl控件, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c839290.jpg) 编辑NotificationControl控件,我们简单的对该控件进行美化,使其看起来更加友好, ~~~   <UserControl x:Class="SilverlightOOBDemo.NotificationControl"       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"       mc:Ignorable="d"       d:DesignHeight="300" d:DesignWidth="400">              <Grid x:Name="LayoutRoot" Background="White">          <Border x:Name="Frame" Width="300" Height="100" Background="LightYellow">              <StackPanel Orientation="Vertical">                  <Border Width="290" Height="24" CornerRadius="4" Margin="2,4,2,4">                      <Border.Background>                          <LinearGradientBrush StartPoint="0.5,0.0"                          EndPoint="0.5,1.0">                              <GradientStop Offset="0.2" Color="#FF1C68A0" />                              <GradientStop Offset="1.0" Color="#FF54A7E2" />                          </LinearGradientBrush>                      </Border.Background>                      <Border.Effect>                          <DropShadowEffect BlurRadius="4" ShadowDepth="4"                          Opacity="0.4" />                      </Border.Effect>                      <TextBlock Text="友情提示" FontSize="12"                      FontWeight="Bold" Foreground="White" Margin="4" />                  </Border>                  <StackPanel Orientation="Horizontal">                      <Image Source="/SilverlightOOBDemo;component/Images/Update.png" Width="48" Height="48"                      Stretch="Fill" Margin="4" VerticalAlignment="Top" />                      <TextBlock Width="240" Text="检测到新的音乐文件,已经更新到播放列表。小广告:我的博客http://jv9.cnblogs.com"                      FontSize="11" Foreground="#FF202020" TextWrapping="Wrap"                      Margin="4" />                  </StackPanel>              </StackPanel>          </Border>      </Grid> </UserControl> ~~~ 然后回到OutofBrowserMainPage页面,这里,我们在“关于”按钮上,添加Click事件响应,使其被点击后,弹出Notifications窗口。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c84aaf0.jpg) 首先创建notifyWindow实例, ~~~   #region Private Members           Window OOBWindow = Application.Current.MainWindow;           NotificationWindow notifyWindow = null;           #endregion              #region Constructor           public OutofBrowserMainPage()           {               InitializeComponent();              notifyWindow = new NotificationWindow();                                   } #endregion ~~~ 然后在Click事件中进行窗口激活: ~~~           private void aboutBtn_Click(object sender, RoutedEventArgs e)           {               if (null == notifyWindow)                   MessageBox.Show("通告窗口仅能运行在OOB模式下,请安装Silverlight应用到本地。");              if (true == App.Current.IsRunningOutOfBrowser)               {                   if (notifyWindow.Visibility == Visibility.Visible)                       notifyWindow.Close();                  NotificationControl myNotify = new NotificationControl();                  notifyWindow.Width = 300;                  notifyWindow.Height = 100;                  notifyWindow.Content = myNotify;                  notifyWindow.Show(10000);              }          } ~~~ 在上面代码中,我们创建了一个新的Notification窗口实例,然后使用Show(毫秒),使其显示在客户端,最终显示效果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c8579c3.jpg) 今天的内容暂时到这里了,下一篇,我们将综合使用这些Silverlight OOB应用开发技巧实现一个完整应用实例, Silverlight Out of Browser音乐播放器。 [本篇源代码下载](http://www.silverlightchina.net/resource/code/SilverlightOOBDemo0726.zip) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)
';

Out of Browser与Office的互操作

最后更新于:2022-04-01 14:20:41

在本篇开始前,首先感谢每一位留下反馈评论的朋友,在我看来,博客不仅仅是简单的分享,同时也是一个学习和发现的过程。在阅读完一篇文章能对其有所评论和提问,也是一种思考的表现。 在上篇“[Silverlight实例教程 - Out of Browser与COM的交互基础](http://www.cnblogs.com/jv9/archive/2010/07/23/1783379.html)”中,我们讨论了Silverlight的OOB应用访问COM组件基础知识,在大家的反馈中,有不少朋友提出疑问,Silverlight对于COM的支持,使其失去跨平台的优越性,另外,Silverlight仅有Out of Browser模式能支持COM,是否仍旧存在较大的局限性? 对此在本篇我们不进行长篇分析和讨论,只是简单的把我的看法说一下。 Silverlight Out of Browser从Silverlight 3 到现在Silverlight 4,一直遵循跨平台的原则,在微软官方有相关的解释, Linux,Moonlight从第一个版本发布,就已经有了高级权限模型,在GtkWidget中Moonlight具有full-trust的能力。 也就是说,Silverlight具有信任权限提升,而Mono具有full-trust模式。 Mac, 由于Mac没有Com的概念,所以,Silverlight的COM无法在Mac中运行,但是微软官方也正在寻找一种方式,尝试使用一种模拟的方式来实现在Mac上运行COM的效果,例如,运行AppleScript ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c66abd2.jpg) 在上面的脚本中可以看出,Mac如何通过AppleScript来调用Office Word的,而这样的方式其实也就是Mac对COM的调用,在以后Silverlight的版本中,如果加入对AppleScripts的支持即可在Mac上支持COM的运行; 从上面的描述来看,Silverlight的OOB应用跨平台,并非不能解决,只是时间的问题。作为技术人员,经常对一门技术的前景进行展望,而需要注意的是,尽量不要使用其短处与其他技术的长处进行相比较,这样的对比结果,只会干扰自己的视线和思路。一门能挣钱的技术,就已经算是一门好技术了。 **Out of Browser与Office的互操作** 言归正传,本篇将继续介绍Silverlight的Out of Browser应用与Office COM组件的交互。相信大家对微软的Office系列并不陌生了,Office在企业项目中使用频率较高,例如在日常项目中经常与遇到导出列表到Excel,或者发送邮件等功能需求,所以微软将其许多功能封装成COM组件,供开发人员使用,增强其应用的灵活性。本篇,我将演示在Silverlight的OOB应用中,如何使用Office Outlook,Word,Excel组件。 我们仍旧使用上篇的项目代码,对其进行扩展,大家可以到上篇下载演示项目代码。   在开始功能代码前,首先需要在UI界面ToolBar中添加三个Button来响应其事件。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c67b0d8.jpg) ~~~   <Border BorderBrush="{StaticResource GlossyBlack_StrokeGradient}" BorderThickness="1" CornerRadius="2" Margin="1" Padding="0,1,1,1">         <StackPanel>               <StackPanel Orientation="Horizontal">                    <Button IsTabStop="False" Width="56" Height="80" Style="{StaticResource BlackGlossyButton}" Margin="1,0,0,0" Foreground="White"  x:Name="sendemailBtn" Click="sendemailBtn_Click">                          <StackPanel>                                <Image VerticalAlignment="Top" HorizontalAlignment="Center" Source="/SilverlightOOBDemo;component/Images/SendEmail.png" Margin="0,-5,0,0" Stretch="None" />                                <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,3,0,0" Text="发邮件" TextWrapping="Wrap"/>                           </StackPanel>                     </Button>                    <Button IsTabStop="False" Width="56" Height="80" Style="{StaticResource BlackGlossyButton}" Margin="1,0,0,0" Foreground="White"  x:Name="excelBtn" Click="excelBtn_Click">                          <StackPanel>                              <Image VerticalAlignment="Top" HorizontalAlignment="Center" Source="/SilverlightOOBDemo;component/Images/Excel.png" Margin="0,-5,0,0" Stretch="None" />                              <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,3,0,0" Text="Excel" TextWrapping="Wrap"/>                          </StackPanel>                    </Button>                    <Button IsTabStop="False" Width="56" Height="80" Style="{StaticResource BlackGlossyButton}" Margin="1,0,0,0" Foreground="White"  x:Name="wordBtn" Click="wordBtn_Click">                          <StackPanel>                              <Image VerticalAlignment="Top" HorizontalAlignment="Center" Source="/SilverlightOOBDemo;component/Images/Word.png" Margin="0,-5,0,0" Stretch="None" />                              <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,3,0,0" Text="Word" TextWrapping="Wrap"/>                          </StackPanel>                    </Button>       </StackPanel>       <TextBlock Foreground="#8FFFFFFF" Text="Office操作" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="2" />       </StackPanel>  </Border> ~~~ 对与三个应用分别添加其Click事件代码。首先,我们先看看OutLook的COM调用, ~~~   private void sendemailBtn_Click(object sender, RoutedEventArgs e)   {               using (dynamic outlook = AutomationFactory.CreateObject("Outlook.Application"))               {                   dynamic mail = outlook.CreateItem(0);                   mail.To = "qq34506@hotmail.com";                   mail.Subject = "来自jv9的问候";                   mail.HTMLBody = "这封邮件是通过Silverlight发送的.";                   mail.Send();                  //mail.Display();  这里是显示出发送邮件的Outlook窗口              }  } ~~~ 在建立Outlook实例后,我们可以使用Outlook.CreateItem来创建新的邮件实例,其中可以简单的设置发送目的邮箱,标题,内容等。在代码后面有mail.Send和Display两个方法。其中如果调用Display,Silverlight会激活Outlook创建邮件窗口,然后用户确认后发送邮件到目的邮箱。例如: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c6894a4.jpg) 而调用mail.Send则会直接发送邮件到目的邮箱。而通常来说,我们建议使用mail.Display,让用户确认后再发送。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c69a6d2.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c6aedef.jpg) **Silverlight操作Office Word** Silverlight操作Office Word比较简单,首先我们添加Word的相应事件: ~~~   private void wordBtn_Click(object sender, RoutedEventArgs e)   {               dynamic word = AutomationFactory.CreateObject("Word.Application");               word.Visible = true;               dynamic doc = word.Documents.Add();                 string Insertxt = "这是Silverlight操作Office Word测试。欢迎大家访问我的博客 http://jv9.cnblogs.com";               dynamic range = doc.Range(0, 0);                 range.Text = Insertxt; } ~~~ 在创建Word实例后,使用Documents.Add创建一个新的空文档,然后,添加相关文档或者图片到Word中。其运行效果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c6bf8c3.jpg) **Silverlight操作Office Excel** 相对上面两个Office组件来讲,Excel的使用较为复杂一点,这里我们来详细演示Silverlight导出Excel的实例。 操作Excel不可缺少的是数据库,作为演示实例,我使用Blend 4创建简单的数据集合,使用Blend创建例程数据集合,我曾经在[Blend实例系列](http://www.cnblogs.com/jv9/archive/2010/03/26/1696594.html)中讲过,这里我将简单的演示, 首先使用Blend 4打开当前SilverlightOOBDemo项目,然后在右边属性栏,选择Data, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c6d1e28.jpg) 这时会提示输入SampleDataSource名称: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c6e1465.jpg) 点击OK后,Blend 4将自动生成一个数据集合。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c70ff92.jpg) 由于是Blend 4自动生成的,其中的String和Number都是随机生成的,这些对于演示实例已经足够了。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c720be5.jpg) 当SampleDataSource创建完成后,在SliverlightOOBDemo项目中,会创建一个SampleData目录,其中包含了我们定义的数据源, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c73ad3c.jpg) 现在,需要在UI中创建一个Datagrid的控件,然后拖动右边Data下SampleDataSource1下的Collection到Datagrid,进行数据绑定,这里我仍旧使用了Blend 4,所有控件和数据绑定,都是简单的拖动即可实现。 ~~~  <sdk:DataGrid x:Name="dgDemo" Margin="10" AutoGenerateColumns="False" ItemsSource="{Binding Collection}" DataContext="{Binding Source={StaticResource SampleDataSource1}}" >       <sdk:DataGrid.Columns>              <sdk:DataGridTextColumn Binding="{Binding Property1}" Header="Property1"/>              <sdk:DataGridTextColumn Binding="{Binding Property2}" Header="Property2"/>              <sdk:DataGridTextColumn Binding="{Binding Property3}" Header="Property3"/>       </sdk:DataGrid.Columns>                                </sdk:DataGrid> ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c74a76e.jpg) 以上设置,我们添加了Sample数据源,并且绑定数据到指定datagrid中,现在,可以设计Excel组件调用代码, ~~~   bool firstTime = true;   public ObservableCollection<Item> itemCollection = new ObservableCollection<Item>();   private void excelBtn_Click(object sender, RoutedEventArgs e)   {               dynamic excel = AutomationFactory.CreateObject("Excel.Application");               excel.Visible = true;                 dynamic workbook = excel.workbooks;               workbook.Add();               dynamic sheet = excel.ActiveSheet;               dynamic cell = null;              int i = 1;              // 将数据传输到Excel              foreach (Item item in dgDemo.ItemsSource)              {                  itemCollection.Add(item);                  cell = sheet.Cells[i, 1]; // 列和行                  cell.Value = item.Property1;                  cell.ColumnWidth = 25;                  cell = sheet.Cells[i, 2];                  cell.Value = item.Property3;                  i++;              }  } ~~~ 在上面代码中,声明一个Excel实例,然后通过循环输入数据源到Excel实例Sheet中,从代码中我们可以看出,输出Excel是通过Cell进行操作的。 这里,我仅输出了Property1和Property3两列。这样就简单的实现了输出Datagrid的数据到Excel了。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c764207.jpg) 现在我们对当前的输出Excel进行一些强化,输入一个图表功能。 对我们当前的代码进行简单的修改,添加如下代码: ~~~   bool firstTime = true;   public ObservableCollection<Item> itemCollection = new ObservableCollection<Item>();   private void excelBtn_Click(object sender, RoutedEventArgs e)   {               dynamic excel = AutomationFactory.CreateObject("Excel.Application");               excel.Visible = true;                 dynamic workbook = excel.workbooks;               workbook.Add();               dynamic sheet = excel.ActiveSheet;               dynamic cell = null;              int i = 1;              // 将数据传输到Excel              foreach (Item item in dgDemo.ItemsSource)              {                  itemCollection.Add(item);                  cell = sheet.Cells[i, 1]; // 列和行                  cell.Value = item.Property1;                  cell.ColumnWidth = 25;                  cell = sheet.Cells[i, 2];                  cell.Value = item.Property3;                  i++;              }              // 创建一个例程图表              dynamic sheetShapes = sheet.Shapes;              sheetShapes.AddChart(-4100, 200, 2, 400, 300);  } ~~~ sheepShapes.AddChart创建一个新的图表效果,其数据是绑定的dynamic sheet = excel.ActiveSheet   这样当我们再次运行输出Excel时,即可得到如下结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c7903cf.jpg) 这些功能的实现,完全是调用了Excel中提供的组件功能。 下面我们更进一步的完善Excel输入功能,添加自动绑定更新事件。其目的是为了实现,当用户输出Excel后,修改Excel中数据,Silverlight的OOB应用中Datagrid同时也更新修改对应数据。 实现该需求,需要用到Excel的SheetChange事件。当用户修改Excel中内容时,即激活该事件。首先,我们需要修改以上代码, ~~~   bool firstTime = true;   public ObservableCollection<Item> itemCollection = new ObservableCollection<Item>();   private void excelBtn_Click(object sender, RoutedEventArgs e)   {               dynamic excel = AutomationFactory.CreateObject("Excel.Application");               excel.Visible = true;                 dynamic workbook = excel.workbooks;               workbook.Add();               dynamic sheet = excel.ActiveSheet;               dynamic cell = null;              int i = 1;              // 将数据传输到Excel              foreach (Item item in dgDemo.ItemsSource)              {                  itemCollection.Add(item);                  cell = sheet.Cells[i, 1]; // 列和行                  cell.Value = item.Property1;                  cell.ColumnWidth = 25;                  cell = sheet.Cells[i, 2];                  cell.Value = item.Property3;                  i++;              }              // 创建一个例程图表              dynamic sheetShapes = sheet.Shapes;              sheetShapes.AddChart(-4100, 200, 2, 400, 300);              // 更新事件              if (firstTime)              {                  excel.SheetChange += new SheetChangedDelegate(SheetChangedEventHandler);                 string sheetName = sheet.Name;                  firstTime = false;              } } ~~~ 为了完成SheetChange,我们需要添加相关事件委托。 ~~~ delegate void SheetChangedDelegate(dynamic excelSheet, dynamic rangeArgs); ~~~ 其具体事件响应Handler为: ~~~           private void SheetChangedEventHandler(dynamic excelSheet, dynamic rangeArgs)           {               dynamic sheet = excelSheet;               string sheetName = sheet.Name;               dynamic range = rangeArgs;               dynamic rowValue = range.Row;               ObservableCollection<Item> entities = itemCollection;               Item[] newEntities = new Item[10];              dynamic col2range = sheet.Range("B1:B10");              for (int i = 0; i < 10; i++)              {                  Item newEntity = new Item();                 newEntity.Property1 = entities[i].Property1;                  newEntity.Property2 = entities[i].Property2;                  dynamic item = col2range.Item(i + 1);                  newEntity.Property3 = Convert.ToInt32(item.Value);                  newEntities[i] = newEntity;              }              dgDemo.ItemsSource = newEntities;              dgDemo.SelectedIndex = Convert.ToInt32(rowValue) - 1;          } ~~~ 这里,我设置操作sheet范围为B1:B10,仅处理这个区域表格中数据绑定,而当excel中数据变化,则会查找对应表格到Datagrid的表格中进行更新。 其运行效果,当用户修改Excel中的B1-B10中的数据,同时Datagrid会产生更新,并且Excel图表也会产生更新效果。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c7a6941.jpg) 上述介绍了Silverlight 4调用Office COM的具体方法,以及常用功能,大家可以在这个基础上进行扩展,将其应用于自己的应用中。 [本篇源代码下载](http://www.silverlightchina.net/resource/code/SilverlightOOBDemo0723.zip) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)    
';

Out of Browser与COM的交互基础

最后更新于:2022-04-01 14:20:38

![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c435fed.png) 相信读过前几篇Silverlight Out of Browser实例教程的朋友已经对Silverlight的OOB应用有了一定的认识和了解。今天,我们将讨论Silverlight Out of Browser的另外一个功能实例,Silverlight OOB与COM API的交互操作。 在开始实例之前,我们先了解一些基本的概念。 **首先说说什么是COM?** 这里我不想过多篇幅的讨论COM和COM+,在微软MSDN对COM技术有详细的解释,[有兴趣的可以看看](http://www.microsoft.com/com/default.mspx)。这里我们只是对COM进行一个简单的描述。所谓COM也就是Componet Object Model,中文称为组件对象模型,通常被用于创建可复用软件组件。在微软的产品中,许多应用都提供了COM接口供开发人员调用。其中较为典型的是Office系列的COM接口。 对于COM和COM+的专业定义,COM是一种说明如何建立可动态互变组件的规范,此规范提供了为保证能够互操作,客户和组件应遵循的一些二进制和网络标准。通过这种标准将可以在任意两个组件之间进行通信而不用考虑其所处的操作环境是否相同、使用的开发语言是否一致以及是否运行于同一台计算机。 而COM+可以称为COM的一个升级版本,其底层结构仍然以COM为基础,它几乎包容了COM的所有内容,COM+综合了COM、DCOM和MTS这些技术要素,它把COM组件软件提升到应用层而不再是底层的软件结构,它通过操作系统的各种支持,使组件对象模型建立在应用层上,把所有组件的底层细节留给操作系统,因此,COM+与操作系统的结合更加紧密。值得注意的是COM+不再局限于COM的组件技术,它更加注重于分布式网络应用的设计和实现。 **Silverlight 4对COM的支持** 早期的Silverlight开发人员都知道,Silverlight作为客户端技术,无法执行权限较高的操作,例如读写本地磁盘,执行本地命令等。Silverlight 4的发布,增加对COM的支持,允许Silverlight在OOB信任应用下,对COM API进行互操作,该功能提高了Silverlight的功能,是其应用如同Windows应用一样,轻松操作Windows API。这里请大家注意,微软给出的建议,Silverlight 4对于COM的支持,仅限于Windows操作系统的COM组件,暂时不能支持用户自定义创建的COM组件,这是目前存在的局限性,不过相信随后的Silverlight版本,会解决这个问题。 **Silverlight 4与COM交互技术基础** 微软为开发人员提供了相关的API,使Silverlight 4和COM交互操作开发简单化。其要点如下: 在Silverlight 4测试版本中与COM交互类是使用[ComAutomationFactory静态类](http://msdn.microsoft.com/en-us/library/system.windows.interop.comautomationfactory(VS.96).aspx),而在Silverlight 4正式版中,微软将[ComAutomationFactory](http://msdn.microsoft.com/en-us/library/system.windows.interop.comautomationfactory(VS.96).aspx)修改为[AutomationFactory](http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.automation.automationfactory(VS.95).aspx)类。 AutomationFactory类是在System.Runtime.InteropServices.Automation命名空间下,提供四个方法和一个属性 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c5db45e.jpg)   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c5eb65e.jpg) ComAutomationFactory.CreateObject和ComAutomationFactory.GetObject用来创建COM实例。 而ComAutomationFactory.GetEvent则是返回一个ComAutomationEvent实例,开发人员可以通过该方法激活相关事件。 ComAutomationFactory.IsAvailable属性将返回一个布尔型,确认该COM组件是否正在被调用。 最后CreateObject<T>()暂时没有任何作用。 其简单的用法: ~~~   private dynamic outlook;   private bool InitializeOutlook()   {       try       {           outlook = AutomationFactory.GetObject("Outlook.Application");            return true;       }      catch (Exception)      {          try          {              outlook = AutomationFactory.CreateObject("Outlook.Application");              outlook.Session.GetDefaultFolder(6 /* Inbox */).Display();              outlook.ActiveWindow.WindowState = 1;               return true;          }          catch (Exception)          {              // 返回错误              return false;          }      }  } ~~~ 在上面代码中,我们可以看到一个新的关键字"**dynamic**",该关键字是C# 4.0的新特性之一,其含义是允许声明一个动态类型的变量,在编译时,编译器允许我们调用任何方法和属性,不会出现异常报错,而在运行时会进行查找调用的方法和属性是否正常,如果方法或者属性存在,并且参数也正确,将会正常调用执行,反之,则返回Microsoft.CSharp.RuntimeBinder.RuntimeBinderException异常错误。对于dynamic关键字的详细解释和更多例程,[](http://msdn.microsoft.com/en-us/library/dd264736(VS.100).aspx)[推荐大家看看MSDN详细](http://msdn.microsoft.com/en-us/library/dd264736(VS.100).aspx)介绍。 在项目中使用dynamic关键字,需要添加新的引用"Microsoft.CSharp", ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c6070e2.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c61da54.jpg) **Silverlight 4与COM交互实例** 相信读过上一篇的朋友都还记得,Silverlight 4默认的情况下仅能访问"My..."系列目录,例如“我的文档”,“我的音乐”,“我的图片”等。而使用COM API后,Silverlight 4将会突破该限制,允许应用访问本地任何磁盘和目录。 **实例**:**在本地任何磁盘和目录写文件和读文件操作** 在本实例中,我们仍旧使用上一篇中的项目代码SilverlightOOBDemo,对其进行简单的修改。 说到本地文件读写操作,很多人都会想到FileSystemObject类,该类提供了简单而又全面的Windows文件操作方法,例如读文件,写文件,删文件,改文件,以及与之相同的目录操作。在MSDN中,有关于[FSO所有的方法列表](http://msdn.microsoft.com/en-us/library/6tkce7xa(v=VS.85).aspx)供大家参考。这里我们会用到CreateTextFile,WriteLine,OpenTextFile,ReadAll等方法实现Silverlight 4操作任何磁盘和目录写文件和读文件。 在项目中的ToolBar栏,添加新的操作按钮, ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c63768d.jpg) ~~~   <Button Width="56" Height="80" Style="{StaticResource BlackGlossyButton}" Margin="1,0,0,0" Foreground="White" x:Name="writeFileBtn" Click="writeFileBtn_Click">        <Button.Content>           <StackPanel>               <Image VerticalAlignment="Top" HorizontalAlignment="Center" Source="/SilverlightOOBDemo;component/Images/Write.png" Margin="0,-5,0,0" Stretch="None" />               <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,3,0,0" Text="写文件" TextWrapping="Wrap"/>           </StackPanel>        </Button.Content>   </Button>  <Button Width="56" Height="80" Style="{StaticResource BlackGlossyButton}" Margin="1,0,0,0" Foreground="White" x:Name="readFileBtn" Click="readFileBtn_Click">       <Button.Content>          <StackPanel>              <Image VerticalAlignment="Top" HorizontalAlignment="Center" Source="/SilverlightOOBDemo;component/Images/Read.png" Margin="0,-5,0,0" Stretch="None" />              <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,3,0,0" Text="读文件" TextWrapping="Wrap"/>          </StackPanel>       </Button.Content>  </Button> ~~~ 为了两个Button创建Click事件,writeFileBtn_Click和readFileBtn_Click。 写文件操作代码: ~~~   private void writeFileBtn_Click(object sender, RoutedEventArgs e)   {       using (dynamic fsoCom = AutomationFactory.CreateObject("Scripting.FileSystemObject"))       {                   dynamic file = fsoCom.CreateTextFile(@"c:/test.txt", true);                   file.WriteLine("Hello Silverlight 4.");                   file.WriteLine("Silverlight写文件到C://");                   file.Close();       }  } ~~~ 运行OOB应用,点击“写文件”按钮,FSO将在C盘创建test文本文件,其内容如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c647284.jpg) 而读文件代码: ~~~ using (dynamic fsoCom = AutomationFactory.CreateObject("Scripting.FileSystemObject"))  {                  dynamic file = fsoCom.OpenTextFile(@"c:/test.txt", 1, true);                  tbResult.Text = file.ReadAll();                  file.Close();  } ~~~ 其运行效果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c658233.jpg) 以上都是使用FSO最基础的文件操作API实现的,依次类推,可以很轻松操作本地文件和目录。 今天Silverlight实例教程暂时介绍到这里,下一篇我将继续介绍Silverlight OOB应用与Office应用的交互。 [本篇源代码下载](http://silverlightchina.net/uploads/soft/100722/1-100H2130925.rar) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)    
';

Out of Browser存取本地文件系统

最后更新于:2022-04-01 14:20:36

在前文,我们讲述了Silverlight Out of Browser的基础以及自定义模式应用。本篇,我们将讲述Silverlight Out of Browser应用的重点 - 创建可信任应用,也称为Trusted Application. 早在Silverlight 3,Silverlight Out of Browser的功能由于权限的限制无法很好的满足用户的正常存取需求,仅能实现将Web应用脱离浏览器。而在Silverlight 4中,通过提升应用信任权限,大大增强了Silverlight Out of Browser的功能,在权限允许的情况下,用户可以自由有访问本地目录,也可以执行本地应用程序,另外通过调用COM组件,实现更多更强大的本地应用操作。下面我们将实例讲述Silverlight Out of Browser可信任应用 - 存取本地文件系统。 本篇中,我们将基于上篇教程提供的项目SilverlightOOBDemo进行演示操作。 首先需要确认SilverlightOOBDemo项目允许用户提升应用信任权限。这样,OOB应用将被允许访问用户本地资源。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c51df0b.jpg) Silverlight 4对于本地文件夹的存取,并非代表存取所有本地磁盘目录,目前为止,Silverlight 4 API仅支持存取“我的文档”,“我的音乐”,“我的图片”和“我的视频”目录以及“Program Files”和“Cookies”目录,而如果想对所有磁盘目录进行访问,则需要使用COM功能进行操作,我们将在下篇讲述,本篇将着重讲述Silverlight 4 API对“我的”系列目录的操作方法。 在实现具体功能前,首先需要为项目添加两个新文件, 一个是资源文件Resources.xaml,该资源文件引用自开源控件BlackLight资源样式,主要目的是为了创建新按钮演示效果,如下图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c531e6a.jpg) 另一个是小图片控件ThumbImage.xaml,该文件是用于载入“我的图片”目录后的图片略缩图,其代码较为简单, ~~~   <UserControl x:Class="SilverlightOOBDemo.ThumbImage"       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"       mc:Ignorable="d"       d:DesignHeight="300" d:DesignWidth="400">      <Grid x:Name="LayoutRoot" Margin="10">          <Image x:Name="ThumbnailImage" Height="145" Width="225" />      </Grid>  </UserControl> ~~~ ~~~   namespace SilverlightOOBDemo   {       public partial class ThumbImage : UserControl       {           private Image _OriginalImage;           public Image OriginalImage            {                get                {                  return _OriginalImage;               }               set               {                  this._OriginalImage = value;                  ThumbnailImage.Source = new WriteableBitmap(_OriginalImage, null);               }           }          public ThumbImage()          {              InitializeComponent();          }      }  } ~~~ 为了能够激活存取事件,我们需要在OutofBrowserMainpage主窗口页面添加按钮控件,其样式调用自资源文件Resources.xaml,对于资源样式调用,这里不再赘述,如果不明白的,请看“[Expression Blend实例中文教程系列文章](http://www.cnblogs.com/jv9/archive/2010/04/11/1709527.html)” ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c543051.jpg) ~~~   <StackPanel x:Name="toolbar" Background="#FF3A3A3A" Grid.ColumnSpan="2" Orientation="Horizontal" Margin="0,0,0,1" Grid.Row="0" >                           <Border BorderBrush="{StaticResource GlossyBlack_StrokeGradient}" BorderThickness="1" CornerRadius="2" Margin="1" Padding="0,1,1,1">                               <StackPanel>                                   <StackPanel Orientation="Horizontal">                                       <Button Width="56" Height="80" Style="{StaticResource BlackGlossyButton}" Margin="1,0,0,0" Foreground="White" x:Name="openFileBtn" Click="openFileBtn_Click">                                          <Button.Content>                                               <StackPanel>                                                   <Image VerticalAlignment="Top" HorizontalAlignment="Center" Source="/SilverlightOOBDemo;component/Images/Open.png" Margin="0,-5,0,0" Stretch="None" />                                                   <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,3,0,0" Text="浏览" TextWrapping="Wrap"/>                                              </StackPanel>                                          </Button.Content>                                      </Button>                                  </StackPanel>                              </StackPanel>                          </Border>                          <Border BorderBrush="{StaticResource GlossyBlack_StrokeGradient}" BorderThickness="1" CornerRadius="2" Margin="1" Padding="0,1,1,1">                              <StackPanel>                                  <StackPanel Orientation="Horizontal">                                      <Button IsTabStop="False" Width="56" Height="80" Style="{StaticResource BlackGlossyButton}" Margin="1,0,0,0" Foreground="White"  x:Name="aboutBtn" Click="">                                          <Button.Content>                                              <StackPanel>                                                  <TextBlock VerticalAlignment="Top" HorizontalAlignment="Center" Text="?" FontSize="20" FontWeight="Bold" Foreground="DarkCyan"  Margin="0,-5,0,0" />                                                  <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,3,0,0" Text="帮助" TextWrapping="Wrap"/>                                             </StackPanel>                                          </Button.Content>                                      </Button>                                  </StackPanel>                              </StackPanel>                         </Border>                      </StackPanel> ~~~ 同时,为了能够载入本地“我的图片”目录中的图片文件,我们需要在OutofBrowserMainpage中使用一个ListBox控件,载入上面我们创建的ThumbImage控件来显示,所有图片略缩图列表, ~~~  <ListBox Grid.Column="0"  x:Name="lsMyPictures" SelectionMode="Single" Style="{StaticResource GlossyBlackListBox}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" BorderBrush="Transparent" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="3,10,0,30" ></ListBox> ~~~ 现在,我们可以为openfilebtn按钮控件创建事件,使其响应用户操作,打开对应目录进行文件浏览 ~~~           private void openFileBtn_Click(object sender, RoutedEventArgs e)           {               if (Application.Current.HasElevatedPermissions)               {                   var imageFiles = Directory.EnumerateFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "*.jpg", SearchOption.AllDirectories);                   foreach (var imagePath in imageFiles)                   {                       AddImageToList(new FileInfo(imagePath));                   }              }          } ~~~ 在上面代码中,如果用户已经提升了OOB应用权限(Application.Current.HasElevatedPermissions),将通过Environment中的GetFolderPath方法获取到本地“My..”目录下的文件,其中Environment.SpecialFolder可以设定特殊目录。更多详细,[请看MSDN解释](http://msdn.microsoft.com/en-us/library/system.environment.specialfolder(VS.95).aspx)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c5544e9.jpg) 在上面代码中,有一个方法AddImageToList,将文件路径信息读取,然后将图片文件信息进行绑定到ListBox。 ~~~           private void AddImageToList(FileInfo fileinfo)           {               FileStream fileStream = fileinfo.OpenRead();               Image img = new Image();               BitmapImage bi = new BitmapImage();               bi.SetSource(fileStream);               img.Margin = new Thickness(5d);               img.Stretch = Stretch.UniformToFill;               img.Source = bi;              try { img.Tag = fileinfo.FullName; }              catch { }              ThumbImage thumbnail = new ThumbImage();              thumbnail.OriginalImage = img;              lsMyPictures.Items.Add(thumbnail);          } ~~~ 在读取“我的图片”目录信息后,将各个图片载入到ThumbImage控件中,然后使用ListBox承载各个图片,这样也就完成了OOB应用对本地目录的浏览。其效果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c567108.jpg) 通过以上的代码,我们可以快速修改,浏览“我的文档”,“我的音乐”和“我的视频”等目录;在OutofBrowserMainPage页面添加代码: ~~~ <ListBox Grid.Column="1"  x:Name="lsMyDocuments" SelectionMode="Single" Style="{StaticResource GlossyBlackListBox}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" BorderBrush="Transparent" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="3,10,0,30" ></ListBox> ~~~ ~~~  private void AddDocToList()          {              var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);              lsMyDocuments.ItemsSource = System.IO.Directory.EnumerateFiles(path);          } ~~~ 然后在openFileBtn_Click事件中调用AddDocToList();即可获取到“我的文档”文件列表, 其他目录与其类似,就不再做代码演示,大家可以自己尝试,如果遇到问题,我们可以一起讨论 。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c57889f.jpg) 看到这里,有的朋友可能会问,既然已经可以实现浏览本地目录功能,是不是也应该可以对本地目录文件进行操作呢?答案是肯定的。当OOB应用获取到权限提升后,则可以使用File类对文件进行操作,例如,移动文件,删除文件等。对目前的项目我们进行简单的修改,演示如何将“我的文档”目录的文件,移动到“我的音乐”目录中,并且删除源目录的相同文件, 首先在OutofBrowserMainPage.xaml页面添加一个新的ListBox,承载“我的音乐”目录文件; ~~~  <StackPanel Orientation="Vertical" Width="200">                                      <TextBlock Text="我的音乐" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"/>                                      <ListBox x:Name="lsMyMusics" SelectionMode="Single" Style="{StaticResource GlossyBlackListBox}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" BorderBrush="Transparent" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="3,10,0,30"></ListBox>                                  </StackPanel> ~~~ 在后台代码添加,浏览载入“我的音乐”目录; ~~~   private void AddMusicToList()           {               var path = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);               lsMyMusics.Items.Clear();               DirectoryInfo myDirectory = new DirectoryInfo(path);               foreach (FileInfo file in myDirectory.EnumerateFiles())               {                   lsMyMusics.Items.Add(file);               }          } ~~~ 简单修改“我的文档”ListBox代码,和后台代码: ~~~  <StackPanel Orientation="Vertical" Width="200">                                      <TextBlock Text="我的文档" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"/>                                      <ListBox x:Name="lsMyDocuments" SelectionMode="Single" Style="{StaticResource GlossyBlackListBox}" ItemContainerStyle="{StaticResource ListBoxItemStyle}" BorderBrush="Transparent" Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="3,10,0,30"></ListBox>                                  </StackPanel> ~~~ ~~~   private void AddDocToList()           {               var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);               lsMyDocuments.Items.Clear();               DirectoryInfo myDirectory = new DirectoryInfo(path);               foreach (FileInfo file in myDirectory.EnumerateFiles())               {                   lsMyDocuments.Items.Add(file);               }              //lsMyDocuments.ItemsSource = System.IO.Directory.EnumerateFiles(path);          } ~~~ 运行后即可得到如下效果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c58e0c6.jpg) 下面我们想实现,点击按钮事件后,将“我的文档”目录中的选中文件,移动到“我的音乐”目录中, 首先,在应用的ToolBar中添加一个移动按钮moveFileBtn ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c5a167f.jpg) 实现moveFileBtn被点击后,移动文件到“我的音乐”目录, ~~~   private void moveFileBtn_Click(object sender, RoutedEventArgs e)           {               FileInfo selectedFile = (FileInfo)lsMyDocuments.SelectedValue;               string path = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);               string formatPath = string.Format("{0}//{1}", path, selectedFile.Name);               if (!File.Exists(formatPath))               {                   File.Move(selectedFile.FullName, formatPath);                   File.Delete(selectedFile.FullName);              }              LoadFiles();          }          private void LoadFiles()          {              AddDocToList();              AddMusicToList();          } ~~~ 这里我们用的是最基本的File文件类操作文件的移动和删除,当然,这需要OOB应用被提升信任权限后,才可以操作,否则,将提示权限错误。 这样,我们就可以查看演示了,当运行应用后,“我的文档”和“我的音乐”两个目录将被载入文件列表,选中“我的文档”中任一文件,然后点击“移动”按钮,就会发现该文件被移动到“我的音乐”目录中,而在“我的文档”中的源文件已经被删除。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eb67c5b1ac8.jpg) 通过上文,我们可以了解到Silverlight Out of Browser的可信任应用对本地目录和文件的操作方法以及基本API的用法,下一篇,我们将通过另外一个实例演示更多Out of Browser的可信任应用的强大功能。 注:本篇部分代码是参考Silverlight开源项目。 [本篇源代码下载](http://silverlightchina.net/uploads/soft/100716/1-100G6162537.zip) 欢迎大家加入"专注Silverlight" 技术讨论群: 32679955(六群) 23413513(五群) 32679922(四群) 100844510(三群) 37891947(二群) 22308706(一群)
';