In my Xaml the values only update when, i go into the xaml and do this for example:
{Binding use.currentlevel}->{Binding use.currentleve}->{Binding use.currentlevel}
but not when the use
variable is updated upon launch and aqustion of data from the database, i cant figure out why.
P.S. i set the bindingcontext in xaml file.
AboutPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="INWORK.Views.AboutPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:control="clr-namespace:ProgressRingControl.Forms.Plugin;assembly=ProgressRing.Forms.Plugin"
xmlns:vm="clr-namespace:INWORK.ViewModels"
Title="{Binding Title}"
BackgroundImage="MainBackground.png">
<ContentPage.BindingContext>
<vm:AboutViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="Accent">#96d1ff</Color>
<Color x:Key="Muscular">#E76F51</Color>
<Color x:Key="Cardio">#429EA6</Color>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="3*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1.15*" />
</Grid.RowDefinitions>
<Ellipse
Grid.Row="1"
Fill="Gray"
HeightRequest="160"
HorizontalOptions="Center"
Stroke="#FFFF9900"
VerticalOptions="Center"
WidthRequest="160" />
<control:ProgressRing
Grid.Row="1"
HeightRequest="100"
Progress="{Binding use.muscularprogress}"
RingProgressColor="{StaticResource Muscular}"
RingThickness="20"
Scale="1"
WidthRequest="100"
class="pro" />
<control:ProgressRing
Grid.Row="1"
HeightRequest="100"
Progress="{Binding use.cardioprogress}"
RingProgressColor="{StaticResource Cardio}"
RingThickness="20"
Scale="0.85"
class="pro" />
<StackLayout Grid.Row="1" VerticalOptions="Center">
<StackLayout Orientation="Horizontal" HorizontalOptions="Center">
<Label
x:Name="Level"
FontAttributes="Bold"
FontSize="20"
HorizontalOptions="CenterAndExpand"
Text="Level "
TextColor="Black" />
<Label
FontAttributes="Bold"
FontSize="20"
HorizontalOptions="CenterAndExpand"
Text="{Binding use.currentlevel}"
TextColor="Black" />
<Button Command="{Binding GoInfoCommand}"></Button>
</StackLayout>
<Label
x:Name="Totalprocent"
FontAttributes="Bold"
FontSize="20"
HorizontalOptions="CenterAndExpand"
Text="0%"
TextColor="Black" />
</StackLayout>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0">
<Label
Padding="2"
FontAttributes="Bold"
FontSize="20"
HorizontalOptions="Center"
Text="Muscular"
TextColor="{StaticResource Muscular}" />
<StackLayout HorizontalOptions="Center" Orientation="Horizontal">
<Label
FontAttributes="Bold"
FontSize="20"
Text="{Binding use.muscularprogress}"
TextColor="Black" />
<Label
FontAttributes="Bold"
FontSize="20"
Text="%"
TextColor="Black" />
</StackLayout>
</StackLayout>
<StackLayout Grid.Column="2">
<Label
x:Name="easier"
FontAttributes="Bold"
FontSize="20"
HorizontalOptions="Center"
Text="Cardio"
TextColor="{StaticResource Cardio}" />
<StackLayout HorizontalOptions="Center" Orientation="Horizontal">
<Label
FontAttributes="Bold"
FontSize="20"
Text="{Binding use.cardioprogress}"
TextColor="Black" />
<Label
FontAttributes="Bold"
FontSize="20"
Text="%"
TextColor="Black" />
</StackLayout>
</StackLayout>
</Grid>
</Grid>
</ContentPage>
LevelProgress.cs Model
using SQLite;
using System;
using System.Collections.Generic;
using System.Text;
namespace INWORK.Models
{
public class LevelProgress
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public int currentlevel { get; set; }
public bool pushups;
public bool squats;
public bool pullups;
public bool splitsquats;
public bool stepups;
public bool tricepdips;
public bool legraises;
//Cardio section
public bool running;
public bool intervals;
public double muscularprogress { get; set; }
public double cardioprogress { get; set; }
}
}
Service for accsessing local database
using INWORK.Models;
using SQLite;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Essentials;
namespace INWORK.Services
{
internal class DataStorage
{
private static SQLiteAsyncConnection db;
private static async Task Init()
{
if (db != null)
return;
var databasePath = Path.Combine(FileSystem.AppDataDirectory, "test2.db");
db = new SQLiteAsyncConnection(databasePath);
await db.CreateTableAsync<LevelProgress>();
await db.CreateTableAsync<Overview>();
}
public static async Task FirstCreation()
{
await Init();
LevelProgress LevelProgress = new LevelProgress()
{
currentlevel = 1,
cardioprogress = 0,
muscularprogress = 0,
pushups = false,
squats = false,
pullups = false,
splitsquats = false,
stepups = false,
tricepdips = false,
legraises = false
};
await db.InsertAsync(LevelProgress);
}
public static async Task EditProgress(LevelProgress usehere)
{
await Init();
await db.UpdateAsync(new LevelProgress()
{
Id = 1,
currentlevel = usehere.currentlevel,
muscularprogress = usehere.muscularprogress,
pushups = usehere.pushups,
squats = usehere.squats,
pullups = usehere.pullups,
splitsquats = usehere.splitsquats,
stepups = usehere.stepups,
tricepdips = usehere.tricepdips,
legraises = usehere.legraises,
cardioprogress = usehere.cardioprogress,
running = usehere.running,
intervals = usehere.intervals
});
}
public static async Task FinishWorkout()
{
}
public static async Task<LevelProgress> GetProgress()
{
await Init();
var levelProgress = await db.Table<LevelProgress>().FirstOrDefaultAsync();
//var levelProgress = await db.Table<LevelProgress>().ToListAsync();
return levelProgress;
}
public static async Task AddWorkout(string _Workout_type, int _Result, DateTime _Date)
{
await Init();
Overview Overview = new Overview()
{
Workout_type = _Workout_type,
Result = _Result,
Date = _Date
};
await db.InsertAsync(Overview);
}
public static async Task<IEnumerable<Overview>> GetOverview(string type)
{
await Init();
IEnumerable<Overview> overview;
if (type == "Running" || type == "Intervals")
{
overview = await db.Table<Overview>().Where(v => v.Workout_type == "Running" || v.Workout_type == "Intervals").ToListAsync();
}
else
{
overview = await db.Table<Overview>().Where(v => v.Workout_type != "Running" || v.Workout_type != "Intervals").ToListAsync();
}
return overview;
}
}
}
AboutViewModel
using INWORK.Models;
using INWORK.Services;
using MvvmHelpers;
using System;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace INWORK.ViewModels
{
public class AboutViewModel : ViewModelBase
{
public ICommand GoInfoCommand { get; set; }
public AboutViewModel()
{
Title = "About";
OpenWebCommand = new Command(async () => await Browser.OpenAsync("https://aka.ms/xamarin-quickstart"));
//Command = "{Binding OpenWebCommand}
Task.Run(async () => await Loadup());
//use.currentlevel = use.currentlevel;
}
private LevelProgress pp;
private LevelProgress _use;
public LevelProgress use
{
get => _use;
set
{
_use = value;
OnPropertyChanged();
}
}
public async Task Loadup()
{
_use = new LevelProgress();
var temps = await DataStorage.GetProgress();
use = temps;
//await ProgressTracker.AddWorkout("Ŗunning",2, DateTime.Today);
if (use.currentlevel == 0)
{
await DataStorage.FirstCreation();
Loadup();
}
}
public ICommand OpenWebCommand { get; }
}
}
CodePudding user response:
You are binding a the Text
value of a Label
to currentleve
property of a LevelProgress
object.
A property can only be bound if it is a BindableProperty
. Thus, you will have to change the definition of currentlevel
(and all other properties you want to bind to!) to make it a bindable.
Do something like this
public class LevelProgress : BindableObject
{
...
public static readonly BindableProperty currentlevelProperty =
BindableProperty.Create("currentlevel", typeof(int), typeof(LevelProgress ), null);
public int currentlevel
{
get { return (int)GetValue(currentlevelProperty ); }
set { SetValue(currentlevelProperty , value); }
}
...
}
Also, refer to the Bindable Property docu.
CodePudding user response:
Yes,if we want to update the UI after we change the field(muscularprogress
,cardioprogress
) in object use
, we need to make class LevelProgress
implement interface INotifyPropertyChanged
.
Since you have has base class ViewModelBase
, we can do like this:
public class LevelProgress: ViewModelBase
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public int currentlevel { get; set; }
public bool pushups;
public bool squats;
public bool pullups;
public bool splitsquats;
public bool stepups;
public bool tricepdips;
public bool legraises;
//Cardio section
public bool running;
public bool intervals;
//public double muscularprogress { get; set; }
private double _muscularprogress;
public double muscularprogress
{
get => _muscularprogress;
set { SetProperty(ref _muscularprogress, value); }
}
//public double cardioprogress { get; set; }
private double _cardioprogress;
public double cardioprogress
{
get => _cardioprogress;
set { SetProperty(ref _cardioprogress, value); }
}
}
Note:
As a test , I created a fake object with special value for it and assign it's value for use
at the beginning,after that we change it's value, and the UI could refresh automatically.
private void test(object obj)
{
use.muscularprogress = 98.8;
use.cardioprogress = 12.9;
}