Xamarin 条目绑定到 MVVM

Xamarin Entry Binding to MVVM

我正在尝试使用 MVVM 而不是代码隐藏来实现我能做的一切,但是如果我有很多对象需要在条目更改时访问,我根本不知道如何做好。

Xaml:

<Entry x:Name="UpdatedCost"                       
       TextChanged="UpdatedCost_TextChanged"/>

<Label x:Name="PriceDifLabel"/>

<Entry x:Name="CurrentCost"
       Text="2.5"/>

<Entry x:Name="CurPriceUpdatedCostProfit"
        Text="22%"/>

代码隐藏:

private void UpdatedCost_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (double.TryParse(e.NewTextValue, out double UpdatedCost))
            {
                double diff = UpdatedCost - double.Parse(CurrentCost.Text);
                string sign = diff > 0 ? "+" : "";
                PriceDifLabel.Text = "(" + sign + string.Format("{0:0.0}", diff) +")";
                PriceDifLabel.TextColor = diff > 0 ? Color.Red : Color.Green;
                PriceDifLabel.BackgroundColor = Color.Yellow;
                CurPriceUpdatedCostProfit.Text = ((int)((double.Parse(CurrentPrice.Text) - UpdatedCost) /
                                                   double.Parse(CurrentPrice.Text) * 100)).ToString() + "%";
            }
            
            
        }

如果能尽可能详细地帮助我将此方法转换为 MVVM 实现,我将不胜感激。如果相关,我的视图模型正在实现 MvvmHelpers.

的 BaseViewModel

非常感谢!

是的,您可以创建模型并为不同的控件创建不同的属性。 我根据您的代码创建了一个简单的演示(以 PriceDifLabel 的文本和文本颜色为例)。

您可以参考以下代码:

1.create 模型 MyViewModel.cs 并实现接口 INotifyPropertyChanged

并且当我们改变UpdatedCost的值时(bind for Entry UpdatedCost),我们也可以相应地改变PriceDif

MyViewModel.cs

   public class MyViewModel: INotifyPropertyChanged
    {
        double _updatedCost;
        public double UpdatedCost
        {
            set { 
                SetProperty(ref _updatedCost, value);
                double diff = UpdatedCost - double.Parse(CurrentCost);
                string sign = diff > 0 ? "+" : "";

                PriceDif = "(" + sign + string.Format("{0:0.0}", diff) + ")";

                PriceDifLabelColor = diff > 0 ? Color.Red : Color.Green;

                System.Diagnostics.Debug.WriteLine("----------> PriceDif = " + PriceDif);
            }

            get { return _updatedCost; }
        }

        string _currentCost;
        public string CurrentCost
        {
            set { SetProperty(ref _currentCost, value); }

            get { return _currentCost; }
        }


        string _priceDif;
        public string PriceDif
        {
            set { SetProperty(ref _priceDif, value); }

            get { return _priceDif; }
        }

        Color _priceDifLabelColor = Color.Green;
        public Color PriceDifLabelColor
        {
            set { SetProperty(ref _priceDifLabelColor, value); }

            get { return _priceDifLabelColor; }
        }
 
        public MyViewModel() {
            CurrentCost = "2.5";
        }   

        bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Object.Equals(storage, value))
                return false;

            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

2.bind 这些属性在 page.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:testapp1="clr-namespace:TestApp1"
             x:Class="TestApp1.TestPage2">

    <ContentPage.BindingContext>
        <testapp1:MyViewModel></testapp1:MyViewModel>
    </ContentPage.BindingContext>
    <ContentPage.Content>
        <StackLayout>
            <Entry x:Name="UpdatedCost" Text="{Binding UpdatedCost}" />

            <Label x:Name="PriceDifLabel" Text="{ Binding PriceDif}" TextColor="{Binding PriceDifLabelColor}"/>

            <Entry x:Name="CurrentCost" Text="2.5"/>

            <Entry x:Name="CurPriceUpdatedCostProfit" Text="22%"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

更多关于INotifyPropertyChanged界面,您可以查看:

https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/binding-mode#viewmodels-and-property-change-notifications.

1.Hello,你可以创建这个BaseViewModel,然后把它传给每一个ViewModel,这样你就不用总是为每一个ViewModel单独创建INotifyPropertyChanged接口了。 然后你可以像这里一样将它继承到任何 ViewModel:

    using YourApp.ViewModels
    ...
    public class YourViewModel : BaseViewModel {
    ....}
    
    //This is the BaseViewModel:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;


    namespace YourApp.ViewModel
    {
    public abstract class BaseViewModel : INotifyPropertyChanged
    {
    //declares the (required) PropertyChanged event that is defined by 
    //the interface.
    public event PropertyChangedEventHandler PropertyChanged;
    // next it is checked if someone has registered for the event,
    // and in this case the event will be raised with the name of the 
    //property being updated.
    protected void OnPropertyChanged([CallerMemberName] string 
    propertyName = "")
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;

        changed.Invoke(this, new 
    PropertyChangedEventArgs(propertyName));
    }
    // This is a helper method to make setting the property easier. 
    // Right now you can just take this with faith
    // or if you are familiar with generics you can study it a little to 
    // see how it works.
    protected bool SetProperty<T>(ref T backingStore, T value,
       [CallerMemberName] string propertyName = "",
       Action onChanged = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value))
            return false;

        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

}

}