许多开发者在从.NET网站开发向Silverlight转型过程中往往都会经历一个比较郁闷的过度期:Silverlight作为镶嵌在网页中的插件,如何能像传统ASP.NET网页一样实现页面切换及参数传递等问题时常捆饶着大家。解决之道我们还得从本质谈起。
ASP.NET网站主要是基于服务器端的开发(runat="server");由于在服务器中运行,因此ASPX动态页面操作的都是服务器端对象,比如访问服务器中的数据库等;而Silverlight则是标准的客户端插件(<object …),如果去掉它的网页外壳(out-of-browser),它的形态与客户端软件几乎无差别,在安全使用范围内它能与用户的电脑直接进行数据交互;相反,如果想通过Silverlight去访问网络上某台服务器中的数据库,则必须劳驾第三者如WCF等作为传输中介。
因此,对于初学Silverlight的朋友我强烈建议大家深刻分清楚 服务器端 与 客户端 的区别,就像当初在学习ASP.NET时,必须分清服务器端控件与客户端控件的区别一样。
大家先看个例子:我们创建一个Silverlight应用程序网站,此时整个解决方案中将包含两个项目分别为Silverlight项目和Web网站项目,为了进行对比分析,我们在Web网站项目中添加一个ASP.NET页面,然后分别在该两个项目中均编写代码一模一样的静态类Global.cs:
public static class Global {
public static int num = 50;
}
接着在Index.aspx页面中添加一个按钮,每次点击时num值增加50:
Index.aspx:
<div>
<asp:Button ID="button1" Text="确定" runat="server" OnClick="button1_OnClick" />
<asp:TextBox ID="textBox1" runat="server" />
</div>
Index.aspx.cs:
protected void button1_OnClick(object sender, EventArgs e) {
Global.num += 50;
textBox1.Text = Global.num.ToString();
}
同样在MainPage.xaml中添加一个按钮,每次点击时num值也增加50:
MainPage.xaml:
<Canvas>
<Button x:Name="button1" Content="确定" Click="button1_Click"/>
<TextBox x:Name="textBox1" Canvas.Left="30" Width="85" />
</Canvas>
MainPage.xaml.cs
private void Button1_Click(object sender, RoutedEventArgs e) {
Global.num += 50;
textBox1.Text = Global.num.ToString();
}
尝试一:用户A访问Index.aspx页面,点击1次button1按钮;接下来用户B也访问该页面,同样也点击1次该按钮;此时用户B电脑中显示的num值是多少?如果用户A接下来又点击了1次该按钮,用户A电脑中的textBox1最终显示的num值是多少?
尝试二:用户A访问Index.aspx页面,点击1次该页面Silverlight程序MainPage中的button1按钮;接下来用户B也访问该页面的Silverlight程序,并点击MainPage中的该按钮1次,此时用户B电脑中显示的num值是多少?如果用户A之后又点击了1次该按钮,用户A电脑中的textBox1最终显示的num值是多少?
这是非常深刻而有意义的例子,答案是什么?大家不妨自己练习一次。
到此,如果大家能充分理解服务器端与客户端的区别,那么Silverlight中的传值就相当好理解了。
在ASP.NET网站开发中,由Index1.aspx跳转到Index2.aspx并传递ID和PWD参数,我们可以在Index1.aspx中通过Response.Redirect("Index2.aspx?ID={0}&PWD={1}",p1,p2);或Server.Transfer("Index2.aspx……");等方式进行操作。而在Silverlight应用程序中,由MainPage1.xaml向MainPage2.xaml切换则必须通过一个包含它们的第三者中介容器器类控件比如Canvas或Grid等。因为虽然它们名字中都有个Page,但确切讲它们并不是页面,而本质是用户控件;因此从一个控件向另一个控件传值必须通过属性或构造函数进行传递,且过程中还得移除掉MainPage1后再添加MainPage2。
按照以上思路,我们首先在MainPage2.xaml.cs中定义好参数的属性或则构造函数参数,例如:
public long ID { get; set; }
public string PWD { get; set; }
或者:
public MainPage2(long id, string pwd) {
InitializeComponent();
}
当需要由MainPage1向MainPage2切换时,在Canvas或Grid中我们先移除掉MainPage1实例:
LayoutRoot.Children.Remove(mainPage1);
然后携带参数创建MainPage2的实例:
MainPage2 mainPage2 = new MainPage2() {
ID = p1,
PWD = p2,
...
};
或者:
MainPage2 mainPage2 = new MainPage2(p1, p2,…);
最后将mainPage2添加进LayoutRoot:
LayoutRoot.Children.add(mainPage2);
到此大家也应该感受到,如果您是初学Silverlight,并且假如您的大脑中里已经驻扎了较深刻的ASP.NET网站开发的知识经验,那么您必须进行思维的转变才能更快的融入到Silverlight的开发中。
接下来我们不妨再往更深层次的方向探索,MainPage的本质是继承自UserControl的用户控件(MainPage : UserControl),那么用户控件的本质又是什么呢?其实不就是类(Class)吗。因此,Silverlight中传值的本质就是类与类之间的属性值传递,此时我们可以尝试将项目中所有的用户控件都删除掉,然后添加同样名字的类进去,让它们分别也继承自UserControl,最后的执行效果一模一样,大家是否已经领悟到什么了?
没错,在传统的ASP.NET网站开发中,我们是如何创建一个带参数的类的实例的,那么在Silverlight中的做法也一模一样;仅有的一点区别是Silverlight中继承自UserControl的类拥有一个UI外壳,很形象的为它们冠以Page的名称描述目的是让开发者从ASP.NET网站开发向Silverlight转型时更加亲切,我们从VisualStudio新建Silverlight应用程序模板中得到证实。
最后再回到本文的开头,我们通过两种尝试体验了静态变量在服务器端与客户端的不同表现,结果也在意料之中,.NET网站中静态变量存储于服务器的内存中,因此所有用户看到且操作的都是同一个变量对象。而Silverlight应用程序中的静态变量则存储于用户各自的电脑内存中,也就是说每个用户操作的都是自己电脑中的对象,这样的特性我们是否也可以将之作为Silverlight传值的媒介呢?
处理时只需Global.args = value;对该全局静态变量进行赋值,然后不论切换到哪个控件,该控件需要参数时直接取用即可。归纳一下:Silverlight中的静态变量在程序的启动之初就驻扎用户电脑内存,不存在多用户并发,不仅方便,高效,自由;而且无须考虑控件的生命周期,实乃Silverlight项目开发的万用利器。
小结:传值仅仅是我们平常开发中会遇到的最常见问题之一,本文通过ASP.NET网页与Silverlight控件的分析对比,目的旨在告诉大家Silverlight运行于客户端上,这句话不仅仅是一个定义,而且还深刻蕴涵着Silverlight的原理以及运行机制,知其然且知其所以然在开发中解决各种问题才能更显游刃有余。