第十八章:MVVM(十)
ViewModels和應用程式生命週期
在移動裝置上的實際計算器程式中,一個重要特性涉及在程式終止時儲存計算器的整個狀態,並在程式再次啟動時恢復它。
再次,ViewModel的概念似乎崩潰了。
當然,可以編寫一些應用程式程式碼來訪問ViewModel的公共屬性並儲存它們,但計算器的狀態也取決於私有欄位。 AdderViewModel的isSumDisplayed和accumulationSum欄位對於恢復計算器的狀態至關重要。
顯而易見,AdderViewModel外部的程式碼無法儲存和恢復AdderViewModel狀態,而ViewModel不會暴露更多公共屬性。只有一個類知道表示ViewModel的整個內部狀態的必要條件,那就是ViewModel本身。
解決方案是讓ViewModel定義儲存和恢復其內部狀態的公共方法。但是因為ViewModel應該努力與平臺無關,所以這些方法不應該使用特定於特定平臺的任何東西。例如,他們不應該訪問Xamarin.Forms Application物件,然後向該Application物件的Properties字典新增專案(或從中檢索專案)。這對於Xamarin.Forms來說太具體了。
但是,在任何.NET環境中都可以使用名為SaveState和RestoreState的方法中的通用IDictionary物件,這就是AdderViewModel實現這些方法的方式:
public class AdderViewModel : ViewModelBase
{
__
public void SaveState(IDictionary<string, object> dictionary)
{
dictionary["CurrentEntry"] = CurrentEntry;
dictionary["HistoryString"] = HistoryString;
dictionary["isSumDisplayed"] = isSumDisplayed;
dictionary["accumulatedSum"] = accumulatedSum;
}
public void RestoreState(IDictionary<string, object> dictionary)
{
CurrentEntry = GetDictionaryEntry(dictionary, "CurrentEntry", "0");
HistoryString = GetDictionaryEntry(dictionary, "HistoryString", "");
isSumDisplayed = GetDictionaryEntry(dictionary, "isSumDisplayed", false);
accumulatedSum = GetDictionaryEntry(dictionary, "accumulatedSum", 0.0);
RefreshCanExecutes();
}
public T GetDictionaryEntry<T>(IDictionary<string, object> dictionary,
string key, T defaultValue)
{
if (dictionary.ContainsKey(key))
return (T)dictionary[key];
return defaultValue;
}
}
涉及儲存和恢復此狀態的AddingMachine中的程式碼主要在App類中實現。 App類使用當前Application類的Properties字典例項化AdderViewModel並呼叫RestoreState。 然後將AdderViewModel作為引數傳遞給AddingMachinePage建構函式:
public class App : Application
{
AdderViewModel adderViewModel;
public App()
{
// Instantiate and initialize ViewModel for page.
adderViewModel = new AdderViewModel();
adderViewModel.RestoreState(Current.Properties);
MainPage = new AddingMachinePage(adderViewModel);
}
protected override void OnStart()
{
// Handle when your app starts.
}
protected override void OnSleep()
{
// Handle when your app sleeps.
adderViewModel.SaveState(Current.Properties);
}
protected override void OnResume()
{
// Handle when your app resumes.
}
}
App類還負責在處理OnSleep方法期間在AdderViewModel上呼叫SaveState。
AddingMachinePage建構函式只需要將AdderViewModel的例項設定為頁面的BindingContext屬性。 程式碼隱藏檔案還管理縱向和橫向佈局之間的切換:
public partial class AddingMachinePage : ContentPage
{
public AddingMachinePage(AdderViewModel viewModel)
{
InitializeComponent();
// Set ViewModel as BindingContext.
BindingContext = viewModel;
}
void OnPageSizeChanged(object sender, EventArgs args)
{
// Portrait mode.
if (Width < Height)
{
mainGrid.RowDefinitions[1].Height = GridLength.Auto;
mainGrid.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Absolute);
Grid.SetRow(keypadGrid, 1);
Grid.SetColumn(keypadGrid, 0);
}
// Landscape mode.
else
{
mainGrid.RowDefinitions[1].Height = new GridLength(0, GridUnitType.Absolute);
mainGrid.ColumnDefinitions[1].Width = GridLength.Auto;
Grid.SetRow(keypadGrid, 0);
Grid.SetColumn(keypadGrid, 1);
}
}
}
AddingMachine程式演示了一種處理ViewModel的方法,但這不是唯一的方法。或者,App可以例項化AdderViewModel,但是可以定義AddingMachineMode的建構函式可以訪問的AdderViewModel型別的屬性。
或者,如果您希望頁面完全控制ViewModel,您也可以這樣做。 AddingMachinePage可以定義自己的OnSleep方法,該方法是從App類中的OnSleep方法呼叫的,頁面類也可以處理AdderViewModel的例項化以及呼叫RestoreState和SaveState方法。但是,對於多頁應用程式,這種方法可能會變得有些笨拙。
在多頁面應用程式中,每個頁面可能都有單獨的ViewModel,可能來自ViewModel,其屬性適用於整個應用程式。在這種情況下,您需要使用相同的字典鍵來避免使用相同名稱的屬性來儲存每個ViewModel的狀態。您可以使用包含類名的更廣泛的字典鍵,例如“AdderViewModel.CurrentEntry”。
雖然資料繫結和ViewModel的功能和優勢現在應該很明顯,但是當與Xamarin.Forms ListView一起使用時,這些功能真的很開心。 這將在下一章中討論。
相關文章
- 第十八章:MVVM(二)MVVM
- 達芬奇密碼 第十八章密碼
- 第十八章 物件導向的特性物件
- 第十週
- Python 第十節 第十七課Python
- 移動端第十八章 rem適配佈局REM
- 第十週週一
- 第十天
- 第十八章:併發程式的基本實現( 多程式 )
- Java第十章Java
- 暑假第十天
- 第十週學習總結
- 第十講 特殊效果操作
- 第十次衝刺
- 衝刺第十天
- Python 第十節 第六課Python
- 第十章 自定義模組
- 十天學會php之第十天 (轉)PHP
- 一個只有十行的精簡MVVM框架MVVM框架
- [每日一題] 第十題:替換空格每日一題
- 用Rust刷leetcode第十題RustLeetCode
- 第十週學習知識總結
- Vue.js第十課 自定義指令Vue.js
- Java基礎 第二節 第十課Java
- Java基礎 第三節 第十課Java
- [第十篇]——Docker 容器連線Docker
- python 第十課 物件導向 2Python物件
- 安卓第十夜 亞當的誕生安卓
- 第十章 MySQL 常用函式MySql函式
- 達芬奇密碼 第十章密碼
- 10日衝刺第十天
- 5.20第十天衝刺
- Mysql系列第十講 常用的幾十個函式詳解MySql函式
- C primer plus 第六版 第十章 第十題 程式設計練習答案程式設計
- 前端早早聊大會 第十期、第十一期報名前端
- 5.4(小組作業十日衝刺第十天)
- PHP 第十週函式學習記錄PHP函式
- Flask教程第十章:郵件支援Flask