第十八章:MVVM(八)

简介:

简单的方法执行
让我们看一个简单的例子。一个名为PowersOfThree的程序允许您使用两个按钮来探索3的各种幂。一个按钮增加指数,另一个按钮减少指数。
PowersViewModel类派生自Xamarin.FormsBook.Toolkit库中的ViewModelBase类,但ViewModel本身位于PowersOfThree应用程序项目中。它不限于3的幂,但构造函数需要一个参数,该类用作功率计算的基值,并作为BaseValue属性公开。因为此属性具有私有集访问器,并且在构造函数结束后不会更改,所以该属性不会触发PropertyChanged事件。
另外两个名为Exponent和Power的属性会触发PropertyChanged事件,但这两个属性也有私有集访问器。 Exponent属性仅从外部按钮单击增加和减少。
为了实现对Button抽头的响应,PowersViewModel类定义了两个类型为ICommand的属性,名为IncreaseExponentCommand和DecreaseExponentCommand。同样,这两个属性都有私有集访问器。如您所见,构造函数通过实例化紧跟构造函数后引用很少私有方法的Command对象来设置这两个属性。调用Command的Execute方法时会调用这两个小方法。 ViewModel使用Command类而不是Command ,因为程序没有使用Execute方法的任何参数:

class PowersViewModel : ViewModelBase
{
    double exponent, power;
    public PowersViewModel(double baseValue)
    {
        // Initialize properties.
        BaseValue = baseValue;
        Exponent = 0;
        // Initialize ICommand properties.
        IncreaseExponentCommand = new Command(ExecuteIncreaseExponent);
        DecreaseExponentCommand = new Command(ExecuteDecreaseExponent);
    }
    void ExecuteIncreaseExponent()
    {
        Exponent += 1;
    }
    void ExecuteDecreaseExponent()
    {
        Exponent -= 1;
    }
    public double BaseValue { private set; get; }
    public double Exponent
    {
        private set
        {
            if (SetProperty(ref exponent, value))
            {
                Power = Math.Pow(BaseValue, exponent);
            }
        }
        get
        {
            return exponent;
        }
    }
    public double Power
    {
        private set { SetProperty(ref power, value); }
        get { return power; }
    }
    public ICommand IncreaseExponentCommand { private set; get; }
    public ICommand DecreaseExponentCommand { private set; get; }
}

ExecuteIncreaseExponent和ExecuteDecreaseExponent方法都会更改Exponent属性(触发PropertyChanged事件),Exponent属性重新计算Power属性,该属性也会触发PropertyChanged事件。
通常,ViewModel将通过将lambda函数传递给Command构造函数来实例化其Command对象。 这种方法允许在ViewModel构造函数中定义这些方法,如下所示:

IncreaseExponentCommand = new Command(() =>
    {
        Exponent += 1;
    });
DecreaseExponentCommand = new Command(() =>
    {
        Exponent -= 1;
    });

PowersOfThreePage XAML文件将三个Label元素的Text属性绑定到PowersViewModel类的BaseValue,Exponent和Power属性,并将两个Button元素的Command属性绑定到ViewModel的IncreaseExponentCommand和DecreaseExponentCommand属性。
注意如何将参数3传递给PowersViewModel的构造函数,因为它在Resources字典中实例化。 将参数传递给ViewModel构造函数是存在x:Arguments标记的主要原因:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:PowersOfThree"
             x:Class="PowersOfThree.PowersOfThreePage">
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:PowersViewModel x:Key="viewModel">
                <x:Arguments>
                    <x:Double>3</x:Double>
                </x:Arguments>
            </local:PowersViewModel>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout BindingContext="{StaticResource viewModel}">
        <StackLayout Orientation="Horizontal"
                     Spacing="0"
                     HorizontalOptions="Center"
                     VerticalOptions="CenterAndExpand">
            <Label FontSize="Large"
                   Text="{Binding BaseValue, StringFormat='{0}'}" />
 
            <Label FontSize="Small"
                   Text="{Binding Exponent, StringFormat='{0}'}" />

            <Label FontSize="Large"
                   Text="{Binding Power, StringFormat=' = {0}'}" />
        </StackLayout>
        <StackLayout Orientation="Horizontal"
                     VerticalOptions="CenterAndExpand">
            <Button Text="Increase"
                    Command="{Binding IncreaseExponentCommand}"
                    HorizontalOptions="CenterAndExpand" />
            <Button Text="Decrease"
                    Command="{Binding DecreaseExponentCommand}"
                    HorizontalOptions="CenterAndExpand" />
        </StackLayout>
    </StackLayout>
</ContentPage> 

这是几次按下一个按钮或另一个按钮后的样子:
2018_10_15_141339
再一次,当需要更改视图时,就会发现将用户界面与底层业务逻辑分离的智慧。 例如,假设您要使用带有TapGestureRecognizer的元素替换按钮。 幸运的是,TapGestureRecognizer有一个Command属性:

<StackLayout Orientation="Horizontal"
             VerticalOptions="CenterAndExpand">
    <Frame OutlineColor="Accent"
           BackgroundColor="Transparent"
           Padding="20, 40"
           HorizontalOptions="CenterAndExpand">
        <Frame.GestureRecognizers>
            <TapGestureRecognizer Command="{Binding IncreaseExponentCommand}" />
        </Frame.GestureRecognizers>
        <Label Text="Increase"
               FontSize="Large" />
    </Frame>
    <Frame OutlineColor="Accent"
           BackgroundColor="Transparent"
           Padding="20, 40"
           HorizontalOptions="CenterAndExpand">
        <Frame.GestureRecognizers>
            <TapGestureRecognizer Command="{Binding DecreaseExponentCommand}" />
        </Frame.GestureRecognizers>
        <Label Text="Decrease"
               FontSize="Large" />
    </Frame>
</StackLayout>

在没有触摸ViewModel或甚至重命名事件处理程序以使其应用于点击而不是按钮的情况下,程序的工作方式相同,但外观不同:
2018_10_15_141655

目录
相关文章
|
存储 SQL 前端开发
借一个项目谈Android应用软件架构,你还在套用MVP 或MVVM吗
借一个项目谈Android应用软件架构,你还在套用MVP 或MVVM吗
|
前端开发 Java 程序员
iOS开发 - 抛开表面看本质之iOS常用架构(MVC,MVP,MVVM)
iOS开发 - 抛开表面看本质之iOS常用架构(MVC,MVP,MVVM)
471 0
|
前端开发
[译] 实用的 MVVM 和 RxSwift
今天我们将使用 RxSwift 实现 MVVM 设计模式。对于那些刚接触 RxSwift 的人,我 在这里 专门做了一个部分来介绍。
1372 0
|
前端开发 JavaScript Android开发
|
前端开发 JavaScript Android开发
|
前端开发 Android开发 Windows
|
前端开发 JavaScript Android开发
|
前端开发 JavaScript Android开发
|
JavaScript 前端开发 Android开发
|
JavaScript 前端开发 Android开发