简体   繁体   English

Xamarin、Label xaml 中的文本不会因属性更改而使用 MVVM 助手更改

[英]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 Labelcurrentleve属性。

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中更改字段( muscularprogresscardioprogress )后更新 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM