1属性未更新Xamarin表单绑定

1属性未更新Xamarin表单绑定,xamarin,mvvm,xamarin.forms,binding,Xamarin,Mvvm,Xamarin.forms,Binding,Xamarin表单中my ContentPage上的一个属性[TripTotal]已绑定到屏幕上的标签,但未更新。我转到属性setter,发现它正在“通知”,请参见下面的Console.WriteLine($“{TripTotal}”)语句,它在启动时会一次性更新。到99.0美元这里有什么问题 From Application output TripTotal 100 TripTotal 101 TripTotal 102 TripTotal 103 TripTotal 104 Tr

Xamarin表单中my ContentPage上的一个属性[TripTotal]已绑定到屏幕上的标签,但未更新。我转到属性setter,发现它正在“通知”,请参见下面的Console.WriteLine($“{TripTotal}”)语句,它在启动时会一次性更新。到99.0美元这里有什么问题

From Application output

TripTotal 100

TripTotal 101

TripTotal 102

TripTotal 103

TripTotal 104

TripTotal 105

TripTotal 106

TripTotal 107

TripTotal 108

TripTotal 109

TripTotal 110



    <?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:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" x:Class="TripCalculator.Views.ExpensePage"
             Title="{Binding Title}" x:Name="BrowseItemsPage">
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
    </ContentPage.ToolbarItems>
    <StackLayout Padding="10">
        <StackLayout Orientation="Horizontal" >
            <Label Text="TripTotal:" FontSize="Title"/>
            <Label Text="{Binding TripTotal, Mode=TwoWay, StringFormat ='${0:F2}'}" x:Name="trip_total" FontSize="Title" HorizontalOptions="End"/>
            <Label Text="{Binding TripTotal_str, Mode=TwoWay}"  FontSize="Title" HorizontalOptions="End"/>
        </StackLayout>
        <BoxView BackgroundColor="Black" HeightRequest="2" WidthRequest="500"/>
        <ListView x:Name="ItemsListView"
                  ItemsSource="{Binding SubTotals}"
                  VerticalOptions="FillAndExpand"
                  HasUnevenRows="true"
                  RefreshCommand="{Binding LoadItemsCommand}"
                  IsPullToRefreshEnabled="true"
                  IsRefreshing="{Binding IsBusy, Mode=OneWay}"
                  CachingStrategy="RecycleElement"
                  ItemSelected="OnItemSelected">  
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Padding="10">
                            <Label Text="{Binding StudentName}"
                                   LineBreakMode="NoWrap"
                                   Style="{DynamicResource ListItemTextStyle}"
                                   FontSize="Subtitle" />
                            <Label Text="{Binding Amount, StringFormat ='${0:F2}'}"       
                                   Style="{DynamicResource ListItemDetailTextStyle}"
                                   FontSize="Subtitle"  />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>
来自应用程序输出的

总数100
总数101
总数102
总数103
总数104
总数105
总数106
总数107
总数108
总数109
总数110

这是ViewModel

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using TripCalculator.Models;
using Newtonsoft.Json;
using Xamarin.Forms;
using System.Windows.Input;
using TripCalculator.Helpers;
using TripCalculator.Views;

namespace TripCalculator.ViewModels
{
    public class ExpenseVM : BaseVM
    {
        public ExpenseVM()
        {
            Title = "Students";
            Expenses = new ObservableCollection<Expense>();
            Messages = new ObservableCollection<string>();
            SubTotals = new ObservableCollection<SubTotal>();
            StudentTotals = new ObservableDictionary<string, double>();
            Expenses.CollectionChanged += (s, e) => TripTotal += 1;
            MessagingCenter.Subscribe<NewExpensePage, Expense>
                (this, "AddItem", async (obj, item) =>
            {
                var newItem = item as Expense;

                await DataSource.AddItemAsync(newItem);

                await this.ExecuteLoadItemsCommand();
            });

        }

        #region OBSERVABLES
        public ICommand LoadItemsCommand
        {
            get
            {
                return new Command (async() => await ExecuteLoadItemsCommand());
            }
        }

        public ICommand UpdateItemCommand
        {
            get
            {
                return new Command<object>(async (id) => await ExecuteUpdateItemCommand(id));
            }
        }

        public Command DeleteCommand
        {
            get
            {
                return new Command (async () => await ExecuteDeleteCommand());
            }
        }

        private Expense selectedItem;
        public Expense SelectedItem {   get => selectedItem;
                                        set => SetProperty(ref selectedItem, value); }
        private ObservableCollection<Expense> expenses;
        public ObservableCollection<Expense> Expenses
        {
            get => expenses;
            set => SetProperty(ref expenses, value);
        }

        private ObservableCollection<SubTotal> subtotals;
        public ObservableCollection<SubTotal> SubTotals
        {
            get => subtotals;
            set => SetProperty(ref subtotals, value);
        }

        public ObservableCollection<string> Students { get { return QueryDistinctNames(); } }

        public ObservableCollection<string> Messages; 

        private ObservableDictionary<string, double> studentTotals;
        public ObservableDictionary<string, double> StudentTotals
        {
            get => studentTotals;
            internal set => SetProperty(ref studentTotals, value);
        }

        double tripTotal = 99;
        public double TripTotal
        {
            get => tripTotal;
            set => SetProperty(ref tripTotal, value);

        }

        public List<string> ExpenseIds { get { return queryAllExpenseIds(); } }

        private void reQueryStudents()
        {
            var studList = Students;
            foreach (string student in studList)
            {
                studentTotals[student] = QueryStudentTotal(student);
            }
            //set Notification cyccle
            this.SubTotals.Clear();
            foreach (var k in studentTotals.Keys)
            {
                subtotals.Add(new SubTotal { Amount = studentTotals[k], StudentName = k });

            }
            //TripTotal = QueryTotal();
            SubTotals = subtotals;

            StudentTotals = studentTotals;

        }

        public double QueryStudentTotal(string student)
        {
            return (from exp in Expenses select exp)
                                .Where(e => e.StudentName == student)
                                .Sum(e => e.Amount);
        }

        internal List<string> queryAllExpenseIds()
        {
            var lst = Expenses.ToList<Expense>();
            // Left As Distinct() although there should be no redundant Id's
            return lst.Select(x => x.Id).Distinct().ToList();
        }

        private double QueryTotal()
        {
            return (from exp in Expenses select exp).Sum(e => e.Amount);
        }

        private ObservableCollection<string> QueryDistinctNames()
        {
            var lst = Expenses.ToList<Expense>();
            List<string> myStudents = lst.Select(x => x.StudentName).Distinct().ToList();
            return myStudents.ToObservableCollection<string>();

        }
        #endregion

        #region CMDS_AND_DATASTORE_OPS
        async Task ExecuteLoadItemsCommand()
        {
            if (IsBusy)
                return;

            IsBusy = true;

            try
            {
                Expenses.Clear();
                if (DataSource != null)
                {
                    var items = await DataSource.GetItemsAsync(true);
                    double sum = 0;
                    foreach (var item in items)
                    {
                        Expenses.Add(item);
                        sum += item.Amount;
                    }
                    reQueryStudents();
                    tripTotal = sum;
                    OnPropertyChanged(nameof(TripTotal));
                }else
                { Console.WriteLine("null Data Store"); }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            finally
            {
                IsBusy = false;
            }
        }

        async Task ExecuteUpdateItemCommand(object newAmt)
        {
            if (IsBusy)
                return;

            IsBusy = true;
            try
            {
                double newCost = (double)newAmt;

                Expense newExpense = new Expense
                {
                    Amount = newCost,
                    StudentName = SelectedItem.StudentName
                };


                var didUpdate = await DataSource.UpdateItemAsync(SelectedItem, newExpense);
                if (didUpdate)
                {  
                    await ExecuteLoadItemsCommand();
                }    
            }
            catch
            {

            }
        }

        private async Task ExecuteDeleteCommand()
        {
            await DataSource.DeleteItemAsync(SelectedItem.Id);
            await ExecuteLoadItemsCommand();
        }
        #endregion

        #region UTIL
        public override string ToString()
        {
            var serializedItem = JsonConvert.SerializeObject(Expenses);
            return serializedItem;
        }

        public void FromString(string json)
        {
            // Hold your hat a bunch of conversions ahead :)
            Expenses = JsonConvert.DeserializeObject<IEnumerable<Expense>>(json)
                                   .ToList()
                                   .ToObservableCollection<Expense>();

        }
        #endregion
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用系统诊断;
使用System.Linq;
使用System.Threading.Tasks;
使用TripCalculator.Models;
使用Newtonsoft.Json;
使用Xamarin.Forms;
使用System.Windows.Input;
使用TripCalculator.Helpers;
使用TripCalculator.Views;
命名空间TripCalculator.ViewModels
{
公共类ExpenseVM:BaseVM
{
公共开支
{
Title=“学生”;
费用=新的可观察到的收款();
消息=新的ObservableCollection();
小计=新的可观察集合();
StudentTotals=新的可观察药物();
费用.CollectionChanged+=(s,e)=>TripTotal+=1;
MessagingCenter。订阅
(此“附加项”,异步(对象,项)=>
{
var newItem=作为费用的项目;
等待DataSource.AddItemAsync(newItem);
等待此命令。ExecuteLoadItemsCommand();
});
}
#区域可观测
公用ICommand加载项命令
{
得到
{
返回新命令(async()=>await ExecuteLoadItemsCommand());
}
}
公共ICommand updateItem命令
{
得到
{
返回新命令(async(id)=>await ExecuteUpdateItemCommand(id));
}
}
公共命令删除命令
{
得到
{
返回新命令(async()=>await executeEleteCommand());
}
}
私人开支;
公共开支SelectedItem{get=>SelectedItem;
set=>SetProperty(ref selectedItem,value);}
私人可观测收款费用;
公共收款费用
{
get=>费用;
set=>SetProperty(参考费用、价值);
}
私人可观测收集小计;
公共可观测集合小计
{
get=>小计;
set=>SetProperty(参考小计,值);
}
公共ObservableCollection学生{get{return QueryDistinctNames();}}
公开收集信息;
私立医科学生总数;
公立医科学生总数
{
get=>studentTotals;
内部集合=>SetProperty(参考studentTotals,值);
}
双倍tripTotal=99;
公共双倍TripTotal
{
get=>tripTotal;
set=>SetProperty(参考tripTotal,值);
}
公共列表ExpenseId{get{return QueryAllexPenseId();}}
私有无效重新查询学生()
{
var studList=学生;
foreach(学生列表中的字符串学生)
{
学生总数[学生]=查询学生总数(学生);
}
//设置通知循环
此.SubTotals.Clear();
foreach(studentTotals.Keys中的变量k)
{
小计.Add(新小计{Amount=studentTotals[k],StudentName=k});
}
//TripTotal=QueryTotal();
小计=小计;
学生总数=学生总数;
}
公共双查询学生总数(字符串学生)
{
返回(从费用中的exp选择exp)
.Where(e=>e.StudentName==student)
.Sum(e=>e.Amount);
}
内部列表queryAllExpenseIds()
{
var lst=费用。ToList();
//保留为Distinct(),但不应存在冗余Id
返回lst.Select(x=>x.Id).Distinct().ToList();
}
私有双QueryTotal()
{
返回(从费用中的exp选择exp).Sum(e=>e.Amount);
}
私有ObservableCollection QueryDistinctNames()
{
var lst=费用。ToList();
List myStudents=lst.Select(x=>x.StudentName).Distinct().ToList();
返回myStudents.ToObservableCollection();
}
#端区
#区域CMDS_和_数据存储_操作
异步任务ExecuteLoadItemsCommand()
{
如果(忙)
返回;
IsBusy=true;
尝试
{
费用;
if(数据源!=null)
{
var items=await DataSource.GetItemsAsync(true);
双和=0;
foreach(项目中的var项目)
{
费用。增加(项目);
总和+=项目金额;
}
reQueryStudents();
tripTotal=总和;
OnPropertyChanged(名称(TripTotal));
}否则
{Console.Wri
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

using TripCalculator.Models;
using TripCalculator.Services;

namespace TripCalculator.ViewModels
{
    public class BaseVM
    {
        protected static IDataSource<Expense> DataSource
        {
            get { return App.DataSource;  }
        }

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

        #region INotifyPropertyChanged

        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);
            if (propertyName=="TripTotal")
            {
                Console.WriteLine($"TripTotal {value}");
            }
            return true;
        }

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

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