[英]Xamarin, Label Text in xaml doesn't change on property changed WITH MVVM Helpers
In my Xaml the values only update when, i go into the xaml and do this for example:在我的Xaml中,值仅在我将 go 插入 xaml 并执行以下操作时更新:
{Binding use.currentlevel}->{Binding use.currentleve}->{Binding use.currentlevel} {绑定使用.currentlevel}->{绑定使用.currentlevel}->{绑定使用.currentlevel}
but not when the use
variable is updated upon launch and aqustion of data from the database, i cant figure out why.但是当
use
变量在启动和从数据库中获取数据时更新时,我不知道为什么。
PS i set the bindingcontext in xaml file. PS 我在 xaml 文件中设置了绑定上下文。
AboutPage.xaml 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 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关于ViewModel
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; }
}
}
You are binding a the Text
value of a Label
to currentleve
property of a LevelProgress
object.您将 Label 的
Text
值绑定到LevelProgress
Label
的currentleve
属性。
A property can only be bound if it is a BindableProperty
.只有当它是
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.因此,您必须更改
currentlevel
的定义(以及您要绑定到的所有其他属性。)以使其成为可绑定的。
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 .另外,请参阅Bindable Property 文档。
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
.是的,如果我们想在 object
use
中更改字段( muscularprogress
, cardioprogress
)后更新 UI,我们需要使 class LevelProgress
实现接口INotifyPropertyChanged
。
Since you have has base class ViewModelBase
, we can do like this:由于您有基础 class
ViewModelBase
,我们可以这样做:
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.作为测试,我创建了一个假的 object 并为其分配特殊值,并在开始时为其分配
use
值,然后我们更改它的值,并且 UI 可以自动刷新。
private void test(object obj)
{
use.muscularprogress = 98.8;
use.cardioprogress = 12.9;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.