最近在做一個SL的項目,做完后,遇到一個F5刷新的問題,本人也是第一次接觸接觸SL項目,記得再ASP.NET瀏覽器的緩存會自動保存最后一次的瀏覽記錄的。
所以就在網上到處找資料,可惜運氣不好,都沒找到合適的資料。基本的解決方法都是通過再HTML頁面增加JS方法,屏蔽F5刷新按鈕的功能,但是這樣的需求並不是我們項目中所要的,還好在BAIDU和群里高手的幫助下,終於大體了解了SL刷新的過程和解決F5刷新返回最后次瀏覽頁面的思想。。
1:SL刷新過程
SL本身就是HTML頁面的一個插件程序,在瀏覽器退出或者F5刷新的時候,SL本身首先調用自身的APP.xaml的 Application_Exit 方法,然后再次進入瀏覽器的時候加載Application_Startup方法,一般都是用Application_Startup 方法去設定SL程序的啟動初始界面。
知道了SL運行的過程我想實現F5刷新問題就不難了,
2:F5刷新解決思路
首先在本地建立獨立存儲(COOKIE也可以,不過不知道為啥用COOKIE的話,SL項目用火狐瀏覽訪問數據就有問題,以待以后研究。)
為了簡單闡述過程,本文的COOKIE就保存3個值:
UserID:用戶賬號信息
PageAddress:最后次瀏覽頁面地址
ExitTime:退出時間
1>系統初始化加載的時候,判斷本地存儲是否有數據,並且判斷當前時間與上次退出時間差 是否小於5秒,(我這里利用5秒作為刷新和重新登錄的標准,當然因人而異)
2>如果上面條件成立,咋直接根據賬號信息,加載系統主界面,並將Navigation 的IFRAM 地址指向本地存儲的上次保存地址即可。
3>如果不成立,顯示登錄界面,並清除本地存儲數據,登錄后重新賦值賬號信息
4>伴隨着SL界面的瀏覽,操作界面的時候同時更新本地存儲的頁面地址值
5>Application_Exit 事件里,增加 slcookie.ExitTime = DateTime.Now.ToString(); 時間的賦值
OK! 整體思路大致如此,現在我將以一個簡短的實例來詳細說明
一、新建項目SLF5
打開VS2010,新建Silverlight應用程序,

並勾選在新網站中承載應用程序

這樣一個SL項目就建立完畢,
接下來需要的就是建立本地存儲類,為了便於理解我就取名SLCookie.cs
View Code
1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation; 10 using System.Windows.Shapes; 11 using System.IO.IsolatedStorage; 12 using System.Text; 13 14 namespace SLF5 15 { 16 /// <summary> 17 /// 功能:SilverLight獨立存儲類 18 /// 創建人:龔安川 19 /// 創建時間:2012-08-18 20 /// </summary> 21 public class SLCookie 22 { 23 /*當前系統Cookie 保存3個字段 24 * PageAddress :記錄最后一次訪問的頁面地址 25 * UserID: 用戶名 26 * ExitTime:退出時間 27 */ 28 29 #region 獨立存儲相關操作函數 30 31 #region 設置Cookie 32 /// <summary> 33 /// 設置Cookie 34 /// </summary> 35 /// <param name="key">the cookie key</param> 36 /// <param name="value">the cookie value</param> 37 public static void SetCookie(string key, string value) 38 { 39 IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings; 40 //判斷該鍵是否存在 41 if (settings.Contains(key)) 42 { 43 settings.Remove(key); 44 settings.Add(key, value); 45 } 46 else 47 { 48 settings.Add(key, value); 49 } 50 settings.Save(); 51 52 } 53 #endregion 54 55 #region 讀取一個已經存在的Cookie 56 /// <summary> 57 /// 讀取一個已經存在的Cookie 58 /// </summary> 59 /// <param name="key">cookie key</param> 60 /// <returns>null if the cookie does not exist, otherwise the cookie value</returns> 61 public static string GetCookie(string key) 62 { 63 IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings; 64 //判斷該鍵是否存在 65 if (settings.Contains(key)) 66 { 67 return settings[key] != null ? settings[key].ToString() : ""; 68 } 69 else 70 { 71 return string.Empty; 72 } 73 } 74 #endregion 75 76 #region 刪除特定的Cookie(清空它的Value值) 77 /// <summary> 78 /// 刪除特定的Cookie(清空它的Value值) 79 /// </summary> 80 /// <param name="key">the cookie key to delete</param> 81 82 public static void DeleteCookie(string key) 83 { 84 IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings; 85 //判斷該鍵是否存在 86 if (settings.Contains(key)) 87 { 88 settings.Remove(key); 89 } 90 } 91 #endregion 92 93 #region 判定指定的key-value對是否在cookie中存在 94 public static bool Exists(String key, String value) 95 { 96 IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings; 97 //判斷該鍵是否存在 98 if (settings.Contains(key)) 99 { 100 return true; 101 } 102 else 103 { 104 return false; 105 } 106 } 107 #endregion 108 109 #region 獲取當前cookie內容 110 public static string getCookieContent() 111 { 112 StringBuilder values = new StringBuilder(); 113 IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings; 114 if (settings != null && settings.Count > 0) 115 { 116 foreach (string item in settings.Keys) 117 { 118 values.Append(settings[item] != null ? settings[item].ToString() : ""); 119 } 120 return values.ToString(); 121 } 122 else 123 { 124 return string.Empty; 125 } 126 } 127 #endregion 128 129 #region 清空本地cookie 130 public static void ClearCookies() 131 { 132 IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings; 133 settings.Clear(); 134 } 135 #endregion 清空本地cookie 136 137 #endregion 138 } 139 }
再為這個基類,寫個輔助類,方便操作調用 SLCookieHelp.cs
View Code
1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation; 10 using System.Windows.Shapes; 11 12 namespace SLF5 13 { 14 /// <summary> 15 /// 功能:SilverLight的Cookie賦值類,用戶獲取歷史信息 16 /// 創建人:龔安川 17 /// 創建時間:2012-08-18 18 /// </summary> 19 public class SLCookieHelp 20 { 21 #region 似有字段 22 private string userid = "UserID"; 23 private string pageaddress = "PageAddress"; 24 private string exittime = "ExitTime"; 25 26 27 #endregion 似有字段 28 29 #region 公共屬性 30 31 #region 登錄賬號 32 /// <summary> 33 /// 登陸名 34 /// </summary> 35 public string UserID 36 { 37 get 38 { 39 return SLCookie.GetCookie(userid); 40 } 41 set 42 { 43 SLCookie.SetCookie(userid, value); 44 } 45 } 46 #endregion 登錄賬號 47 48 #region 歷史地址 49 /// <summary> 50 /// 歷史地址 51 /// </summary> 52 public string PageAddress 53 { 54 get 55 { 56 return SLCookie.GetCookie(pageaddress); 57 } 58 set 59 { 60 SLCookie.SetCookie(pageaddress, value); 61 } 62 } 63 64 #endregion 歷史地址 65 66 #region 退出時間 67 /// <summary> 68 /// 退出時間 69 /// </summary> 70 public string ExitTime 71 { 72 get 73 { 74 return SLCookie.GetCookie(exittime); 75 } 76 set 77 { 78 SLCookie.SetCookie(exittime, value); 79 } 80 } 81 82 #endregion 歷史地址 83 84 #endregion 公共屬性 85 86 //清空COOKIE方法 87 public void ClearCookie() 88 { 89 SLCookie.ClearCookies(); 90 } 91 } 92 }
接下來再APP.XAML.CS的啟動事件增加判斷,確定進入哪個界面,在退出事件里面修改本地存儲登陸時間的更新。
一般情況下,在啟動事件里面根據本地存儲的數據判斷啟動不同的用戶控件即可,但是本人這個項目正好用到了,基框架界面加載的方式,就順便在這里也跟大家一起分享了。
現在的代碼如下:
View Code
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Documents; 8 using System.Windows.Input; 9 using System.Windows.Media; 10 using System.Windows.Media.Animation; 11 using System.Windows.Shapes; 12 13 namespace SLF5 14 { 15 public partial class App : Application 16 { 17 //本地COOKIE操作類 18 SLCookieHelp slcookie = new SLCookieHelp(); 19 20 public App() 21 { 22 this.Startup += this.Application_Startup; 23 this.Exit += this.Application_Exit; 24 this.UnhandledException += this.Application_UnhandledException; 25 26 InitializeComponent(); 27 } 28 29 private void Application_Startup(object sender, StartupEventArgs e) 30 { 31 //一般情況下根據本地存儲的數據進行判斷,指向RootVisual 啟動不同的界面即可 32 //this.RootVisual = new MainPage(); 33 //this.RootVisual = new Login(); 34 //基框架界面加載方式 35 Host host = new Host(); 36 this.RootVisual = host; 37 38 //存儲已經創建的容器 39 AppContext.Host = host; 40 AppContext.IsAdministrator = false; 41 } 42 43 private void Application_Exit(object sender, EventArgs e) 44 { 45 slcookie.ExitTime = DateTime.Now.ToString(); 46 } 47 48 private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) 49 { 50 // 如果應用程序是在調試器外運行的,則使用瀏覽器的 51 // 異常機制報告該異常。在 IE 上,將在狀態欄中用一個 52 // 黃色警報圖標來顯示該異常,而 Firefox 則會顯示一個腳本錯誤。 53 if (!System.Diagnostics.Debugger.IsAttached) 54 { 55 56 // 注意: 這使應用程序可以在已引發異常但尚未處理該異常的情況下 57 // 繼續運行。 58 // 對於生產應用程序,此錯誤處理應替換為向網站報告錯誤 59 // 並停止應用程序。 60 e.Handled = true; 61 Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); }); 62 } 63 } 64 65 private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e) 66 { 67 try 68 { 69 string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace; 70 errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n"); 71 72 System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");"); 73 } 74 catch (Exception) 75 { 76 } 77 } 78 } 79 }
基框架界面加載用到了以下幾個類:
用戶控件:Host.xaml
XAML代碼新建后不動即可,cs代碼如下:
View Code
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Documents; 8 using System.Windows.Input; 9 using System.Windows.Media; 10 using System.Windows.Media.Animation; 11 using System.Windows.Shapes; 12 13 namespace SLF5 14 { 15 /// <summary> 16 /// 系統容器外殼,用於承載主業務界面(login;mainpage) 17 /// 加載順序(RootVisual-Host-Login-MainPage) 18 /// </summary> 19 public partial class Host : UserControl,IHost 20 { 21 public Host() 22 { 23 InitializeComponent(); 24 //默認設置為登錄界面 25 SetChild(new Login()); 26 Context.Host = this; 27 } 28 29 private void SetChild(UserControl userControl) 30 { 31 LayoutRoot.Children.Clear(); 32 LayoutRoot.Children.Add(userControl); 33 } 34 35 public void SetRootVisual(UIElement content) 36 { 37 UserControl uc = content as UserControl; 38 if (uc == null) 39 { 40 throw new Exception("Content is not a UserControl"); 41 } 42 SetChild(uc); 43 } 44 45 /// <summary> 46 /// 系統注銷方法,注銷后將返回登錄界面 47 /// 注銷動作由MainPage觸發,將清空用戶所有數據 48 /// </summary> 49 public void LoginOff() 50 { 51 AppContext.LogOff = false; 52 Context.Host.SetRootVisual(new Login()); 53 } 54 55 } 56 }
接口類:IHost.cs
View Code
1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation; 10 using System.Windows.Shapes; 11 12 namespace SLF5 13 { 14 public interface IHost 15 { 16 void SetRootVisual(UIElement content); 17 void LoginOff(); 18 } 19 }
存儲全局變量類:Context.cs 以及 AppContext.cs
View Code
1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation; 10 using System.Windows.Shapes; 11 12 namespace SLF5 13 { 14 /// <summary> 15 /// 上下文環境,存儲全局共享數據 16 /// </summary> 17 public class Context 18 { 19 /// <summary> 20 /// 用於標識用戶是否登錄系統 21 /// </summary> 22 public static bool LoginFlag = false; 23 24 public static IHost Host; 25 } 26 }
View Code
1 using System; 2 using System.Net; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Documents; 6 using System.Windows.Ink; 7 using System.Windows.Input; 8 using System.Windows.Media; 9 using System.Windows.Media.Animation; 10 using System.Windows.Shapes; 11 12 namespace SLF5 13 { 14 public static class AppContext 15 { 16 //當前UI容器 17 public static Host Host; 18 19 //用戶登錄狀態 20 public static bool LogOff = false; 21 22 //判斷用戶的角色是否是管理員(默認管理員) 23 public static bool IsAdministrator = true; 24 // //數據菜單集合 25 //public static List<TreeViewModel> ListTreeData; 26 27 } 28 }
接下來我們建立幾個測試的頁面:A.XAML,B.XAML.Default.XAML 以便多頁面的切換,每個界面寫一些自己標記的信息即可
登陸界面:Login.XAML
就是界面放2個LABEL和2個文本框,默認賬號和密碼都是:admin ,具體的項目當然要去查詢數據庫了。
重點來說MainPage界面的構造:
添加程序集:System.Windows.Controls.Navigation 的引用,在項目中添加引用,.NET下面就可以找到該程序集
主界面我利用GRID的2列,
左側列放一個LISTBOX 來顯示項目切換的頁面地址信息(類似與菜單吧),
右側列放置一個navigation 控件,利用此控件的IFRAM指向不同的界面信息。
XAML的源碼如下:
View Code
<UserControl x:Class="SLF5.MainPage" 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:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"></ColumnDefinition> <ColumnDefinition Width="*"></ColumnDefinition> </Grid.ColumnDefinitions> <!--左側導航菜單--> <ListBox SelectionChanged="ListBox_SelectionChanged"> <ListBoxItem Content="A頁面"> <ListBoxItem.ContentTemplate> <DataTemplate x:Name="myTemplate"> <TextBlock Foreground="Blue" Text="{Binding}" /> </DataTemplate> </ListBoxItem.ContentTemplate> </ListBoxItem> <ListBoxItem Content="B頁面" ContentTemplate="{Binding ElementName=myTemplate}"></ListBoxItem> </ListBox> <!--右側顯示區--> <Border Grid.Column="1" Grid.Row="2" CornerRadius="4" Background="#CC166C9F" BorderBrush="#99154270" BorderThickness="1"> <navigation:Frame x:Name="Contnetframe" JournalOwnership="UsesParentJournal"/> </Border> </Grid> </UserControl>
好了這樣項目所需要的准備工作就已經做完,項目如下:

接下來開始我們的工作了,
在MainPage.Xaml.cs
定義本地存儲輔助類
//本地cookie 類
SLCookieHelp slcookie = new SLCookieHelp();
增加界面加載事件 Loaded += new RoutedEventHandler(MainPage_Loaded);
View Code
1 string url = @"/Default.xaml"; 2 if (!string.IsNullOrWhiteSpace(slcookie.PageAddress)) 3 { 4 url = slcookie.PageAddress; 5 } 6 Contnetframe.Navigate(new Uri(url, UriKind.Relative));
通過上面來加載顯示的頁面地址
然后在LISTBOX的選擇事件,對本地存儲的地址進行更新
View Code
1 //選擇項改變事件 2 private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 3 { 4 string url = @"/A.xaml"; 5 ListBox lst = sender as ListBox; 6 if (lst.SelectedItem == null) return; 7 ListBoxItem item = lst.SelectedItem as ListBoxItem; 8 if (item.Content.ToString() == "B頁面") 9 { 10 url = @"/B.xaml"; 11 } 12 //保存當前頁面 13 slcookie.PageAddress = url; 14 //跳轉連接 15 Contnetframe.Navigate(new Uri(url, UriKind.Relative)); 16 }
這樣主界面的工作就完成了,
最后再登陸界面的加載事件增加本地存儲的判斷以及登陸事件的本地存儲賬戶信息的賦值即可
方法如下:
View Code
1 //加載事件 2 void Login_Loaded(object sender, RoutedEventArgs e) 3 { 4 //如果本地COOKIE有值 直接進入界面 5 if (slcookie != null && !string.IsNullOrWhiteSpace(slcookie.UserID) && !string.IsNullOrWhiteSpace(slcookie.ExitTime)) 6 { 7 //判斷退出時間和登陸時差是否大於5秒 8 DateTime now = DateTime.Now; 9 DateTime exit = Convert.ToDateTime(slcookie.ExitTime); 10 TimeSpan ts = now - exit; 11 //當操作時間小於5秒默認為刷新 12 if (ts.TotalSeconds < 5 && ts.TotalSeconds > 0) 13 { 14 MainPage mainpage = new MainPage(); 15 Context.Host.SetRootVisual(mainpage); 16 } 17 else 18 { 19 //清空本地COOKIE 20 slcookie.ClearCookie(); 21 } 22 } 23 }
View Code
1 //登陸 2 private void btnLogin_Click(object sender, RoutedEventArgs e) 3 { 4 if (string.IsNullOrWhiteSpace(txtuid.Text) || string.IsNullOrWhiteSpace(txtpwd.Text)) 5 { 6 MessageBox.Show("用戶名和密碼不可為空"); 7 return; 8 } 9 10 if (txtuid.Text == "admin" && txtpwd.Text == "admin") 11 { 12 slcookie.UserID = "admin"; 13 MainPage mainpage = new MainPage(); 14 Context.Host.SetRootVisual(mainpage); 15 } 16 else 17 { 18 MessageBox.Show("用戶名和密碼輸入不正確"); 19 } 20 }
OK!完工,這樣一個基本的SL程序的刷新功能就完成了,因為也是第一次做SL項目,當然肯定有考慮不周或者有更好的辦法解決此問題,還我希望論壇的大俠們給予指導,如果寫的不對的地方還望大家給予拍磚,虛心接受大家的評論。
運行效果如下:
源碼地址:http://files.cnblogs.com/82767136/SLF5.rar
