Silverlight 和 WPF 一脉相承,很多东西基本类似或一致。对了,Silverlight 早期的名字叫 WPF/E,由此可见一斑。Silverlight 拥有自己的 CLR / DLR,还有一个具有相当规模的的 BCL 库。从某种意义上来说,它几乎就是个 "嵌入式操作系统"。用 Silverlight 开发一个 RIA 方式的 NetOS,应该没啥问题,远比现在的 WebOS 要 "酷" 很多。
Silverlight 除了可以执行基于 CLR / DLR 的托管代码外,还支持用 JavaScript API 来调用。不过既然其主打是 RIA,我们自然没理由放弃 C#,而改用 JavaScript 来开发应用了。
Silverlight Applicaton Model 对使用过 WPF 或者 WinForm 的程序员来说,都不会陌生。
1. 生命周期
(1) 用户访问包含 Silverlight 应用的页面。
(2) Silverlight Plug-in 被载入,下载 Silverlight XAP 文件。
(3) Silverlight Plug-in 从 XAP 中读取 AppMainfest.xml,创建运行环境并载入程序集文件。
(4) Silverlight Plug-in 创建 Application 对象实例 (App.xaml, App.xaml.cs)。
(5) 通过构造方法触发 Application.Startup 事件,该事件将创建 Root Visual,这通常是应用的主页面。
(6) 执行应用程序功能。
(7) 当用户关闭浏览器、网页跳转、刷新,或者用 JavaScript 移除 Silverlight 都会导致当前 Application 关闭,并触发 Exit 事件。
2. Application.Events
打开 App.xaml.cs,你会看到相关的事件处理代码。
{
public App()
{
this.Startup += this.Application_Startup;
this.Exit += this.Application_Exit;
this.UnhandledException += this.Application_UnhandledException;
InitializeComponent();
}
}
(1) Application.StartUp
StartUp 事件用于指定 RootVisual 对象实例。需要注意的是,RootVisual 仅在第一次修改时有效,也就是说它是一种特殊的 "只读" 模式。
{
this.RootVisual = new MainPage();
}
试试看。
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Application.Current.RootVisual = new UserControl();
MessageBox.Show((Object.ReferenceEquals(Application.Current.RootVisual, this)).ToString());
}
}
尽管对 RootVisual 没有触发异常,但输出结果表明,RootVisual 依然指向 MainPage。作为变通手段,我们可以用下面这种方式来替换主页面。
{
this.RootVisual = new Grid();
(this.RootVisual as Grid).Children.Add(new MainPage());
}
RootVisual 不能改,那就该 RootVisual.Children 好了。
除了指定 RootVisual 外,我们还可以处理初始化参数。这类似 GUI / CUI 的执行参数 Main (string[] args)。在包含 Silverlight 的 HTML 页面,我们可以指定相关的参数。
...
<param name="initParams" value="a=1,b=Hello" />
...
</object>
参数名称 "initParams",使用 "," 分割多个 KeyValuePair。
{
this.RootVisual = new MainPage();
var sb = new System.Text.StringBuilder();
foreach (var kv in e.InitParams)
{
sb.AppendFormat("{0}={1}/n", kv.Key, kv.Value);
}
MessageBox.Show(sb.ToString());
}
(2) Application.Exit
Exit 事件使得我们在关闭应用时,可以执行一些额外的处理,比如存储相关数据。
{
MessageBox.Show("Exit!");
}
很好。无论是关闭页面,刷新页面还是跳转到其他页,我们都能看到这个可爱的 "Exit!"。
(3) Application.UnhandledException
UnhandledException 中的注释很好,它给那些不愿深究的 "懒人" 们一个很好的提示。通过 e.Handle 我们可以在处理异常后继续执行应用。ReportErrorToDOM() 还展示了如何和 HtmlPage 进行交互,包括执行 JavaScript 代码。
{
// If the app is running outside of the debugger then report the exception using
// the browser's exception mechanism. On IE this will display it a yellow alert
// icon in the status bar and Firefox will display a script error.
if (!System.Diagnostics.Debugger.IsAttached)
{
// NOTE: This will allow the application to continue running after an exception has been thrown
// but not handled.
// For production applications this error handling should be replaced with something that will
// report the error to the website and stop the application.
e.Handled = true;
Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
}
}
private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
{
try
{
string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
errorMsg = errorMsg.Replace('"', '/'').Replace("/r/n", @"/n");
HtmlPage.Window.Eval("throw new Error(/"Unhandled Error in Silverlight Application " + errorMsg + "/");");
}
catch (Exception)
{
}
}