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