Josè Mourinho的專欄 http://blog.csdn.net/zyc13701469860轉載請註明原作者和出處。
有些時候我們需要儲存應用程式的設定,如使用者的系統設定。在Android中,我們可以使用sharepreference。在Metro中我們該怎麼做呢?
儲存/讀取基本類型資料 Metro程式會把要儲存的資料寫入ApplicationData.Current.LocalSettings字典中,並儲存在本地。程式在開始啟動並執行時候會從本地初始化該字典。載入之前儲存的資料。這樣我們就可以方便的儲存/讀取基本類型資料了。我將其封裝成了一個工具類。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.Storage;namespace Win8_Study.Pages{ class LocalDataUtil { #region 儲存/讀取基本類型資料 public static void SaveData(string key, object value) { ApplicationData.Current.LocalSettings.Values[key] = value; } public static object GetData(string key) { return ApplicationData.Current.LocalSettings.Values[key]; } public static void RemoveData(string key) { ApplicationData.Current.LocalSettings.Values.Remove(key); } #endregion }}
下面我們來看一個樣本:
預設顯示的字型大小為24,我們將其字型改為28後返回到首頁面,然後重新進入該頁面。你會發現字型的大小變為28了。重新啟動程式進入該頁面,你會發現字型的大小仍然為28。下拉式清單的選中項與字型大小是時刻對應的.
實現方法如下:1.每次進入該頁面的時候,首先擷取之前儲存的字型大小a.沒有擷取到將字型大小設為預設值b.擷取到將字型大小設為擷取的值2.使用者改變字型大小時,儲存改變後的值
public sealed partial class LocalDataPage : Win8_Study.Common.LayoutAwarePage { private readonly string TEXT_VALUE = "國米_百度百科\n" + "國際米蘭足球俱樂部(Football Club Internazionale Milano,簡稱 Inter 或 Internazionale)" + "是一家位於意大利北部倫巴第區米蘭市的足球俱樂部。"; private readonly double TEXT_FONT_SIZE = 24; private readonly string TEXT_FONT_SIZE_KEY = "LocalDataPage-TEXT_FONT_SIZE_KEY"; public LocalDataPage() { this.InitializeComponent(); } protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState) { Init(); } private void Init() { //首先讀取之前儲存的設定,如果為空白設定成預設狀態 InitFontSize(); leftTextBlock.Text = TEXT_VALUE; } protected override void SaveState(Dictionary<String, Object> pageState) { } #region 儲存程式設定 private void OnLeftComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { var comboBox = sender as ComboBox; var item = comboBox.SelectedItem as ComboBoxItem; SetTextFontSize(Convert.ToDouble(item.Content)); } private void SetTextFontSize(double size) { leftTextBlock.FontSize = size; LocalDataUtil.SaveData(TEXT_FONT_SIZE_KEY, size); } private void InitFontSize() { var obj = LocalDataUtil.GetData(TEXT_FONT_SIZE_KEY); double size = TEXT_FONT_SIZE; if (obj != null) { size = Convert.ToDouble(obj); } foreach (var element in leftFontSizeComboBox.Items) { var item = element as ComboBoxItem; if (item.Content.ToString().Equals(size.ToString())) { leftFontSizeComboBox.SelectedItem = item; break; } } } #endregion ... }
或許你會嘗試著用這種方法去非基本類型的資料(比如Page,Color什麼的)。嘿嘿,掛了吧。那麼我們該怎樣去儲存非基本類型的資料呢?比如一個包含學生資訊的集合?
儲存/讀取非基本類型的資料--序列化/還原序列化儲存程式的即時資料是十分必要的。比如你從網路上擷取了一些娛樂新聞並顯示給使用者,你需要將這些資料儲存下來,以便程式下次啟動並執行時候使用。下次運行程式的時候,這些資料就會變成本地的了,載入速度會非常快,因為你不需要再去從網路擷取資料。如果你不這樣做的話,使用者可能會在網路非常擁塞的情況下看到一個非常"乾淨"的螢幕。這個時候你的應用也許會被(應該是必須)。。。
舉一個"稍微"複雜點的例子現在有Student,Coder兩個類,它們都繼承了父類People。
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.Text;using System.Threading.Tasks;namespace Win8_Study.Pages{ [DataContract] public abstract class People { [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } public People(string name,int age) { this.Name = name; this.Age = age; } } [DataContract] public class Student : People { [DataMember] public int Score { get; set; } public Student(string name, int age, int score) : base(name, age) { this.Score = score; } } [DataContract] public class Coder : People { [DataMember] public int WorkYears { get; set; } public Coder(string name, int age, int workYears) : base(name, age) { this.WorkYears = workYears; } }}
我們需要在ListView上隨機顯示一些學生和程式員的資訊,並儲存下來。然後清空ListView,讀取儲存的資料,看結果與之前的是否相同。
建立學生和程式員資訊的方法很簡單,在這裡建立5-10條資訊,每條資訊的內容隨機顯示:
private List<People> GetPeopleDatas() { List<People> peoples = new List<People>(); Random ran = new Random(DateTime.Now.Millisecond); int count = ran.Next(5) + 5;//5 - 10 for (int i = 0; i < count; ++i) { int type = ran.Next(2); if (type == 0) { peoples.Add(new Student("學生" + (i + 1), ran.Next(12) + 6, 60 + ran.Next(41))); } else { peoples.Add(new Coder("程式員" + (i + 1), ran.Next(10) + 22, ran.Next(5))); } } return peoples; }
根據類別建立不同ListView項
private void OnRightRandomAddDataButtonClicked(object sender, RoutedEventArgs e) { _peoples = GetPeopleDatas(); SetListViewData(_peoples); }
private void SetListViewData(List<People> peoples) { itemListView.Items.Clear(); foreach (People p in peoples) { ListViewItem item = new ListViewItem(); item.FontSize = 20; if (p is Student) { Student s = p as Student; item.Content = string.Format("{0} 年齡:{1} 成績: {2}", s.Name, s.Age, s.Score); } else { Coder c = p as Coder; item.Content = string.Format("{0} 年齡:{1} 工作時間: {2}年", c.Name, c.Age, c.WorkYears); } itemListView.Items.Add(item); } }
儲存資料
private async void OnRightSaveDataButtonClicked(object sender, RoutedEventArgs e) { await SerializerUtil.XMLSerialize(_peoples,typeof(List<People>)); await PopupUtil.ShowMessageDialog(string.Format("儲存資料成功! item數量{0}",_peoples.Count), "提示"); }
注意到People,Student,Coder中的序列化標誌的嗎?不添加的話是無法序列化的。其中 SerializerUtil.XMLSerialize是我封裝的序列化代碼的方法,其實現方式如下:
public static async Task XMLSerialize(object instance, Type type) { //取得當前程式存放資料的目錄 StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder; //定義檔案名稱 string fileName = "LocalDataPage-list_data.xml"; //建立檔案,如果檔案存在就覆蓋 StorageFile newFile = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting) //將內容序列化至檔案 Stream newFileStream = await newFile.OpenStreamForWriteAsync(); DataContractSerializer ser = new DataContractSerializer(type, GetTypes()); ser.WriteObject(newFileStream, instance); newFileStream.Dispose(); }
注意GetTypes()方法,在序列化的時候需要指定序列化對象的類型集合。在這裡需要序列化的資料類型有3個:People,Student,Coder。所以我們應該這樣設定:
private static ObservableCollection<Type> GetTypes() { //添加要序列化的類型 if (_Types == null) { _Types = new ObservableCollection<Type>(); _Types.Add(typeof(People)); _Types.Add(typeof(Student)); _Types.Add(typeof(Coder)); } return _Types; }
其中_Types是全域對象ObservableCollection<Type>。至此,資料就儲存好了。
讀取資料讀取資料也就是進行還原序列化,我們可以得到之前儲存的對象集合,其資料類型是List<People>,然後我們將該對象集合交給ListView顯示即可。
private async void OnRightLoadDataButtonClicked(object sender, RoutedEventArgs e) { try { var obj = await SerializerUtil.XMLDeserialize(typeof(List<People>)); _peoples = obj as List<People>; SetListViewData(_peoples); await PopupUtil.ShowMessageDialog(string.Format("讀取資料成功! item數量{0}", _peoples.Count), "提示"); return; } catch (FileNotFoundException) { } await PopupUtil.ShowMessageDialog("你還沒有儲存資料。", "提示"); }
還原序列化
public static async Task<object> XMLDeserialize(Type type) { StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder; string fileName = "LocalDataPage-list_data.xml"; StorageFile newFile = await folder.GetFileAsync(fileName); Stream newFileStream = await newFile.OpenStreamForReadAsync(); //進行還原序列化 DataContractSerializer ser = new DataContractSerializer(type, GetTypes()); object instance = ser.ReadObject(newFileStream); newFileStream.Dispose(); return instance; }
可以看到讀取的資料與之前儲存的相同.我們的目的達到了。
程式啟動並執行效果如下:1.隨機顯示學生和程式員資訊:
2.儲存資料儲存檔案的內容
<ArrayOfPeople xmlns="http://schemas.datacontract.org/2004/07/Win8_Study.Pages" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><People i:type="Student"><Age>14</Age><Name>學生1</Name><Score>66</Score></People><People i:type="Coder"><Age>24</Age><Name>程式員2</Name><WorkYears>4</WorkYears></People><People i:type="Student"><Age>7</Age><Name>學生3</Name><Score>86</Score></People><People i:type="Coder"><Age>23</Age><Name>程式員4</Name><WorkYears>1</WorkYears></People><People i:type="Coder"><Age>25</Age><Name>程式員5</Name><WorkYears>2</WorkYears></People></ArrayOfPeople>
3.清除資料並讀取之前儲存的資料顯示效果同第一張圖.
專欄網址:http://blog.csdn.net/zyc13701469860/article/details/8194090