Home > database >  Binding values not working on Xamarin Forms
Binding values not working on Xamarin Forms

Time:04-24

I am building an application on Xamarin Forms using MVVM. The problem is that when I run the app, the data does not appear, the values ​​are default. But if I change something in the Xaml file, in the name of the binding property, that value is updated and appears as it should be without restarting the application. I mention that I initialized BindingContext in ViewModel.

Here is the code:

ViewModel:

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

The Xaml file:

<?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>

The Xaml.cs file:

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

And the 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
    }
}

CodePudding user response:

GetDefaultScreen is setting the value of the public field

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

instead, you need to set the value of the public properties

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