簡體   English   中英

綁定值不適用於 Xamarin Forms

[英]Binding values not working on Xamarin Forms

我正在使用 MVVM 在 Xamarin Forms 上構建應用程序。 問題是當我運行應用程序時,數據沒有出現,值是默認值。 但是,如果我在 Xaml 文件中以綁定屬性的名稱更改某些內容,則該值將更新並顯示為應有的樣子,而無需重新啟動應用程序。 我提到我在 ViewModel 中初始化了 BindingContext。

這是代碼:

視圖模型:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinApp.Services;
using XamarinApp.Views.Month;

namespace XamarinApp.ViewModels.Month
{
    public class DefaultScreenViewModel : BaseViewModel
    {
        private readonly IMonthService _monthService;
        public decimal budget;
        public decimal spendings;
        public decimal economies;
        public decimal percent;
        public DefaultScreenViewModel(IMonthService monthService)
        {
            _monthService = monthService;
            UpdateBudgetCommand = new Command(async () => await GoToUpdateBudget());
            Title= "My Money";
        }
        public async void GetDefaultScreen()
        {
            try
            {
                var screen = await _monthService.GetDefaultScreen();
                budget = screen.Budget;
                economies = screen.Economies;
                spendings = screen.Spendings;
                percent = spendings/budget;

               
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        public decimal Budget
        {
            get => budget;
            set => OnPropertyChanged(nameof(Budget));
        }
        public decimal Spendings
        {
            get => spendings;
            set => OnPropertyChanged(nameof(Spendings));
        }
        public decimal Economies
        {
            get => economies;
            set => OnPropertyChanged(nameof(Economies));
        }
        public decimal Percent
        {
            get => percent;
            set => OnPropertyChanged(nameof(Percent));
        }

        private async Task GoToUpdateBudget()
            => await Shell.Current.GoToAsync(nameof(UpdateBudgetPage));

        public ICommand UpdateBudgetCommand { get; }
    }
}

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:month="clr-namespace:XamarinApp.ViewModels.Month" 
             x:Class="XamarinApp.Views.Month.DefaultScreenPage"
             BackgroundColor="{StaticResource BackgroundColor}"
             Title="{Binding Title}">
    <ContentPage.Content>
       
        <StackLayout>
            <Frame Padding="30" Margin="30" BackgroundColor="{StaticResource Primary}">

                <StackLayout>
                        <StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
                        <StackLayout Orientation="Vertical" FlexLayout.AlignSelf="Start" HorizontalOptions="FillAndExpand">
                            <Label Text="{Binding Spendings}" FontSize="Subtitle" VerticalOptions="FillAndExpand" />
                            <Label Text="Spendings" FontSize="Subtitle" VerticalOptions="FillAndExpand"/>
                            
                        </StackLayout>
                        <StackLayout Orientation="Vertical" FlexLayout.AlignSelf="End" HorizontalOptions="End">
                            <Label Text="{Binding Budget}" FontSize="Subtitle" VerticalOptions="FillAndExpand" />
                            <Label Text="Budget" FontSize="Subtitle" VerticalOptions="FillAndExpand"/>
                            
                        </StackLayout>
                        
                        </StackLayout>
                        <ProgressBar Progress="{Binding Percent}" BackgroundColor="#69B811" ProgressColor="#750909" FlexLayout.AlignSelf="Center" Margin="10"/>
                    <Label/>
                    <Label Text="Current Month Savings: " />
                    <Label Text="{Binding Economies}"/>
                </StackLayout>
        </Frame>
        <Button Text="Update your budget" Command="{Binding UpdateBudgetCommand}" Margin="20,40,20,0" CornerRadius="10"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Xaml.cs 文件:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XamarinApp.ViewModels.Month;

namespace XamarinApp.Views.Month
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class DefaultScreenPage : ContentPage
    {
        public readonly DefaultScreenViewModel _defaultScreenViewModel;
        public DefaultScreenPage()
        {
            InitializeComponent();
            _defaultScreenViewModel = Startup.Resolve<DefaultScreenViewModel>();
            BindingContext = _defaultScreenViewModel;
        }
        protected override void OnAppearing()
        {
            _defaultScreenViewModel?.GetDefaultScreen();
        }
    }
}

和 BaseViewModel:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

using Xamarin.Forms;

using XamarinApp.Models;
using XamarinApp.Services;

namespace XamarinApp.ViewModels
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public IDataStore<Item> DataStore => DependencyService.Get<IDataStore<Item>>();

        bool isBusy = false;
        public bool IsBusy
        {
            get { return isBusy; }
            set { SetProperty(ref isBusy, value); }
        }

        string title = string.Empty;
        public string Title
        {
            get { return title; }
            set { SetProperty(ref title, value); }
        }

        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;
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;

            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}

GetDefaultScreen正在設置公共字段的值

var screen = await _monthService.GetDefaultScreen();
budget = screen.Budget;
economies = screen.Economies;
spendings = screen.Spendings;
percent = spendings/budget;

相反,您需要設置公共屬性的值

var screen = await _monthService.GetDefaultScreen();
Budget = screen.Budget;
Economies = screen.Economies;
Spendings = screen.Spendings;
Percent = spendings/budget;

回復“我忘記輸入字段 = 值”(在設置器中)。

這是一種簡化設置器的方法。 在一些 mvvm 庫中使用,並顯示在Xamarin Forms 綁定模式中。

在您的BaseViewModel class 中,添加此方法:

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;
}

那么每個屬性就是:

private decimal budget;
public decimal Budget
{
    get => budget;
    set => SetProperty(ref budget, value);
}

注意:屬性名稱在編譯時通過可選第三個參數的[CallerMemberName]屬性自動獲取。

注意:字段budget )通常是private的。 沒有其他 class 應該使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM