本文共 3983 字,大约阅读时间需要 13 分钟。
在移动设备上的实际计算器程序中,一个重要特性涉及在程序终止时保存计算器的整个状态,并在程序再次启动时恢复它。
再次,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(IDictionarydictionary) { dictionary["CurrentEntry"] = CurrentEntry; dictionary["HistoryString"] = HistoryString; dictionary["isSumDisplayed"] = isSumDisplayed; dictionary["accumulatedSum"] = accumulatedSum; } public void RestoreState(IDictionary 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 (IDictionary 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一起使用时,这些功能真的很开心。 这将在下一章中讨论。转载地址:http://bwaal.baihongyu.com/