一、按模組分包
一般大型的Silverlight應用,都會按模組分解成多個silverlight project,編譯後就有多個xap包,然後在需要用到的情境按需載入。我近期開發的這個項目不需要全站Silverlight,而是aspx混合silverlight,說得更白點,就是把相應的子模組xap包嵌入aspx.
這樣分包就簡單多了:直接用js控制dom元素,修改object元素中的source,動態設定成不同的xap即可實現無重新整理的載入不同模組。(這比網上主流的方式:用WebClient動態下載xap包,最終再反射載入,個人覺得更簡單。當然,這種方式不適用於整站Silverlight的項目)
二、按需反射載入xap中的頁面
上面討論的辦法,只是解決了按需載入不同的xap檔案,但是如果一個xap中有多個頁面,如何確定載入某個xap後,顯示其中的哪個頁面呢?
答案:參數傳入+反射
silvelright以object標籤嵌入html時,可以指定一些傳入參數,類似下面這樣:
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="ClientBin/Basic.xap" /> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50826.0" /> <param name="autoUpgrade" value="true" /> <param name="initParams" value="page=Basic.City" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration: none"> <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style: none" /> </a> </object>
注意其中的<param name="initParams" value="page=Basic.City"/>這表明我們想讓City頁面在載入成功後顯示。
那麼,SL中如何接受這個參數呢?看下面的代碼:
private void Application_Startup(object sender, StartupEventArgs e) { //檢測有無傳入參數 if (e.InitParams != null && e.InitParams.ContainsKey("page")) { string _pageName = e.InitParams["page"]; //根據page參數,動態反射載入相應的執行個體 Assembly asm = this.GetType().Assembly; UserControl _page = asm.CreateInstance(_pageName) as UserControl; this.RootVisual = _page; } else { //如果沒有參數傳入,則顯示預設頁面 this.RootVisual = new Airport(); } }
三、SEO最佳化
這是RIA應用經常會遇到的一個問題,前面提到的處理方法並未涉及這一塊,預設情況下:xap模組的動態載入,以及根據參數動態反射載入不同頁面,都不會改變瀏覽器的地址,所以搜尋引擎會始終認為這是一個頁面,最終也只能收錄一個網址。
為了對搜尋引擎更友好,可以在地址欄的#部分做些手腳,最終要到達的效果:
如果動態載入Basic.xap模組,且顯示該模組中的City頁面時,我們可以讓地址欄類似: http://localhost:1223/Default.aspx#Basic|Basic.City
切換到User.xap模組(即使用者管理模組),且顯示該模組中的User頁面時,我們可以讓地址欄類似:http://localhost:1223/Default.aspx#User|User.User
這樣,雖然都是同一個default.aspx頁面,但是搜尋引擎卻認為這是二個不同的url,會搜錄二個地址。
default.aspx完整代碼如下:
<%@ Page Language="c#" AutoEventWireup="true" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Silverlight SEO最佳化及分包下載</title> <style type="text/css"> html, body { height: 100%; overflow: auto; font-size:12px; } body { padding: 0; margin: 0; } #silverlightControlHost { height: 100%; text-align: center; } #nav { line-height:30px; text-align: center; background: #efefef; padding: 5px; } #nav a { padding: 0px 10px; } </style> <script type="text/javascript" src="Silverlight.js"></script> <script type="text/javascript" src="jquery-1.6.4.min.js"></script> <script type="text/javascript"> function onSilverlightError(sender, args) { var appSource = ""; if (sender != null && sender != 0) { appSource = sender.getHost().Source; } var errorType = args.ErrorType; var iErrorCode = args.ErrorCode; if (errorType == "ImageError" || errorType == "MediaError") { return; } var errMsg = "Unhandled Error in Silverlight Application " + appSource + "\n"; errMsg += "Code: " + iErrorCode + " \n"; errMsg += "Category: " + errorType + " \n"; errMsg += "Message: " + args.ErrorMessage + " \n"; if (errorType == "ParserError") { errMsg += "File: " + args.xamlFile + " \n"; errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } else if (errorType == "RuntimeError") { if (args.lineNumber != 0) { errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } errMsg += "MethodName: " + args.methodName + " \n"; } throw new Error(errMsg); } //載入Silverlight function loadSilverlight(url) { if (url.indexOf("#") == -1) {return;} var _param = url.split('#')[1]; var _sl = document.getElementById("sl"); var _xap = _param.split('|')[0] + ".xap"; var _page = _param.split('|')[1]; _sl.innerHTML = "<object data='data:application/x-silverlight-2,' type='application/x-silverlight-2' width='100%' height='100%'><param name='source' value='ClientBin/" + _xap + "' /><param name='onError' value='onSilverlightError' /><param name='background' value='white' /><param name='minRuntimeVersion' value='4.0.50826.0' /><param name='autoUpgrade' value='true' /><param name='initParams' value='page=" + _page + "' /><a href='http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0' style='text-decoration: none'><img src='http://go.microsoft.com/fwlink/?LinkId=161376' alt='Get Microsoft Silverlight' style='border-style: none' /></a></object>"; } $().ready(function () { loadSilverlight(window.location.href); }) </script></head><body> <form id="form1" runat="server" style="height: 100%"> <div id="silverlightControlHost"> <div id="nav"> Silvelight分包以及SEO樣本 (by 菩提樹下的楊過 http://yjmyzz.cnblogs.com/):<br/> <a href="#Basic|Basic.City" onclick="loadSilverlight(this.href)">城市管理</a> | <a href="#Basic|Basic.Airport" onclick="loadSilverlight(this.href)">航站管理</a> | <a href="#User|User.User" onclick="loadSilverlight(this.href)">使用者管理</a> | <a href="#User|User.Organization" onclick="loadSilverlight(this.href)">組織機構管理</a> </div> <div id="sl"> <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="ClientBin/Basic.xap" /> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50826.0" /> <param name="autoUpgrade" value="true" /> <param name="initParams" value="page=Basic.City" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration: none"> <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style: none" /> </a> </object> </div> <iframe id="_sl_historyFrame" style="visibility: hidden; height: 0px; width: 0px; border: 0px"></iframe> </div> </form></body></html>
樣本原始碼: http://files.cnblogs.com/yjmyzz/ReflectorXap.7z