ObservableCollection 没有正确加载数据
ObservableCollection not loading data correctly
只是我正在尝试做的一些背景知识,我有一个 syncfusion listview
可以通过 REST api 调用更新数据库中的数据。我得到每周数据。视图上还有另一个按钮,应该用每月数据更新列表。
对于每周,我在数据库中有 1 条记录,列表中填充了数据。单击“查看全部”按钮后,数据库提供数据,列表收到 13 条记录,但视图仅更新其中一条。看起来列表仅限于显示一个。这是代码:
private ObservableCollection<TransactionInformationDto> listItems;
public ObservableCollection<TransactionChartData> ChartData { get; set; }
public ObservableCollection<TransactionInformationDto> TransactionList
{
get { return listItems; }
set { listItems = value; OnPropertyChanged(nameof(TransactionList)); }
}
public ICommand GetTransactions => new Command(async () =>
{
IsBusy = true;
TransactionList.Clear();
var data = await GetAllTransactions();
foreach(var item in data)
{
TransactionList.Add(item);
}
IsBusy = false;
});
public Command<object> ItemTappedCommand
{
get
{
return this.itemTappedCommand ?? (this.itemTappedCommand = new Command<object>(ShowTransactionInformation));
}
}
private void ShowTransactionInformation(object item)
{
var list = item as Syncfusion.ListView.XForms.ItemTappedEventArgs;
var transaction = (TransactionInformationDto)list.ItemData;
Navigation.PushAsync(new TransactionInfoPage(transaction));
}
#endregion
#region Constructor
public DashboardPageViewModel(INavigation navigation)
{
LoadTransactionDetails();
Navigation = navigation;
}
#endregion
#region Properties
public double TotalBalance
{
get
{
return totalBalance;
}
set
{
this.totalBalance = value;
this.OnPropertyChanged();
}
}
public INavigation Navigation { get; }
#endregion
#region Methods
private async Task<ObservableCollection<TransactionInformationDto>> GetAllTransactions()
{
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
return new ObservableCollection<TransactionInformationDto>(await DependencyService.Get<IGetInformation>().GetAllUserTransactions(retrievalInformation));
}
private void LoadTransactionDetails()
{
var userTransactions = new List<TransactionInformationDto>();
Task.Run(async () => {
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
var userBalance = await DependencyService.Get<IGetInformation>().GetUserBalanceInformation(retrievalInformation);
TotalBalance = userBalance.CurrentBalance;
userTransactions = await DependencyService.Get<IGetInformation>().GetTransactionData(retrievalInformation);
});
Thread.Sleep(1000);
WeekData(userTransactions);
}
private void WeekData(List<TransactionInformationDto> transactionInformation)
{
TransactionList = new ObservableCollection<TransactionInformationDto>();
var data = new ObservableCollection<TransactionInformationDto>(transactionInformation.OrderByDescending(x =>x.TimeStamp));
foreach(var item in data)
{
TransactionList.Add(item);
}
days = new string[] { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
ChartData = new ObservableCollection<TransactionChartData>();
UpdateChartData(days);
}
XAML
<Grid Grid.Row="1">
<Label Margin="16,26,16,16"
Text="TRANSACTIONS"
TextColor="{StaticResource Gray-800}"
FontSize="12"
LineHeight="{OnPlatform Android=1.5, Default=-1}"
HorizontalOptions="Start" />
<buttons:SfButton Margin="11,26,11,16"
BorderWidth="0"
TextColor="{StaticResource Gray-600}"
BackgroundColor="{StaticResource Transparent}"
WidthRequest="72"
HeightRequest="18"
Command="{Binding GetTransactions}"
CornerRadius="4"
HorizontalOptions="End">
<Label Text="VIEW ALL"
TextColor="{DynamicResource Link}"
FontSize="12"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
LineHeight="{OnPlatform Android=1.5, Default=-1}"
/>
</buttons:SfButton>
</Grid>
<listView:SfListView Grid.Row="2"
x:Name="_transactionList"
IsScrollBarVisible="False"
ItemSpacing="0"
ItemsSource="{Binding TransactionList}"
SelectionBackgroundColor="{StaticResource TappedBackgroundColor}"
TapCommand="{Binding ItemTappedCommand}"
AutoFitMode="Height"
BackgroundColor="White">
<listView:SfListView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--Profile pic-->
<border:SfBorder Grid.RowSpan="3"
Margin="16"
WidthRequest="40"
HeightRequest="40"
CornerRadius="20"
BorderWidth="0"
VerticalOptions="Center">
<Image Aspect="Fill"
Source="receipt">
</Image>
</border:SfBorder>
<!-- Name -->
<Label Grid.Column="1"
Margin="0,15,0,4"
HorizontalOptions="Start"
Text="{Binding ReceiverName}"
LineHeight="{OnPlatform Android=1.5, Default=-1}" />
<!-- Transaction Title -->
<Label Grid.Row="1"
Grid.Column="1"
Margin="0,0,0,16"
HorizontalOptions="Start"
Text="{Binding TransactionMessage}"
TextColor="{StaticResource Gray-700}"
FontSize="12"
LineHeight="{OnPlatform Android=1.5, Default=-1}" />
<!-- Amount -->
<Label Grid.Column="1"
Margin="0,16,16,4"
HorizontalOptions="End"
TextColor="{Binding IsReceived, Converter={x:StaticResource BooleanToColorConverter}, ConverterParameter=5}"
LineHeight="{OnPlatform Android=1.5, Default=-1}">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding IsReceived, Converter={StaticResource BooleanToStringConverter}, ConverterParameter=2}" />
<Span Text=" $" />
<Span Text="{Binding TransactionAmount}" />
</FormattedString>
</Label.FormattedText>
</Label>
<!-- Date -->
<Label Grid.Row="1"
Grid.Column="1"
Margin="0,0,16,16"
HorizontalOptions="End"
Text="{Binding TimeStamp, StringFormat='{}{0:dd MMM yyyy}'}"
TextColor="{StaticResource Gray-700}"
FontSize="12"
LineHeight="{OnPlatform Android=1.5, Default=-1}" />
<!-- Seperator -->
<BoxView Grid.Row="2" Grid.ColumnSpan="2" Style="{StaticResource SeparatorStyle}" />
</Grid>
</DataTemplate>
</listView:SfListView.ItemTemplate>
</listView:SfListView>
<controls:Popup Grid.Row="2" Grid.RowSpan="1" IsBusy="{Binding IsBusy}" IsEnabled="{Binding IsBusy}" LoadingMessage="Loading the list.." />
</Grid>`
如有任何帮助,我们将不胜感激。
- 永远不要使用 Thread.Sleep()。如果它在 UI 线程上 运行,它会阻止 UI(UI 挂起/不响应)。
1.1。尝试通过添加 Thread.Sleep() 和 Task.Delay() 来解决某些问题是走向地狱的一步。不要输入此路径!
- 您不需要在任何地方都使用 ObservableCollection。如果不需要可观察性,请使用 IList 或 IEnumerable 或数组。
- Task.Run() 创建一个新线程。你通常不需要这个。 + 你在数据绑定方面有问题,因为你需要确保绑定在 UI 线程上执行,以便能够更新 UI 组件。
- 不要在构造函数中加载数据。触发加载和生命周期事件,如 PageAppearing() (https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/app-lifecycle)
更新代码
private ObservableCollection<TransactionInformationDto> listItems;
public ObservableCollection<TransactionChartData> ChartData { get; set; }
public ObservableCollection<TransactionInformationDto> TransactionList
{
get { return listItems; }
set { listItems = value; OnPropertyChanged(nameof(TransactionList)); }
}
public ICommand GetTransactions => new Command(async () =>
{
IsBusy = true;
TransactionList.Clear();
var data = await GetAllTransactions();
TransactionList = new ObservableCollection<TransactionInformationDto>(data);
IsBusy = false;
});
public Command<object> ItemTappedCommand
{
get
{
return this.itemTappedCommand ?? (this.itemTappedCommand = new Command<object>(ShowTransactionInformation));
}
}
private void ShowTransactionInformation(object item)
{
var list = item as Syncfusion.ListView.XForms.ItemTappedEventArgs;
var transaction = (TransactionInformationDto)list.ItemData;
Navigation.PushAsync(new TransactionInfoPage(transaction));
}
#endregion
#region Constructor
public DashboardPageViewModel(INavigation navigation)
{
// LoadTransactionDetails(); // <<< see 4.
Navigation = navigation;
}
#endregion
#region Properties
public double TotalBalance
{
get
{
return totalBalance;
}
set
{
this.totalBalance = value;
this.OnPropertyChanged();
}
}
public INavigation Navigation { get; }
#endregion
#region Methods
private async Task<IEnumerable<TransactionInformationDto>> GetAllTransactions() // see 2.
{
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
return await DependencyService.Get<IGetInformation>().GetAllUserTransactions(retrievalInformation);
}
private async Task LoadTransactionDetails()
{
var userTransactions = new List<TransactionInformationDto>();
// see 3.
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
var userBalance = await DependencyService.Get<IGetInformation>().GetUserBalanceInformation(retrievalInformation);
TotalBalance = userBalance.CurrentBalance;
userTransactions = await DependencyService.Get<IGetInformation>().GetTransactionData(retrievalInformation);
// see. 1. & 1.1.
WeekData(userTransactions);
}
private void WeekData(List<TransactionInformationDto> transactionInformation)
{
TransactionList = new ObservableCollection<TransactionInformationDto>(transactionInformation.OrderByDescending(x =>x.TimeStamp));
days = new string[] { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
ChartData = new ObservableCollection<TransactionChartData>();
UpdateChartData(days);
}
Task.Run 方法将 运行 在尝试更新 UI 的单独线程上。在主线程中添加项目时,布局将更新。 UI 线程被中断,这限制了应用程序中的布局。
https://docs.microsoft.com/en-us/xamarin/ios/user-interface/ios-ui/ui-thread#background-thread-example
https://forums.xamarin.com/discussion/comment/96756
只是我正在尝试做的一些背景知识,我有一个 syncfusion listview
可以通过 REST api 调用更新数据库中的数据。我得到每周数据。视图上还有另一个按钮,应该用每月数据更新列表。
对于每周,我在数据库中有 1 条记录,列表中填充了数据。单击“查看全部”按钮后,数据库提供数据,列表收到 13 条记录,但视图仅更新其中一条。看起来列表仅限于显示一个。这是代码:
private ObservableCollection<TransactionInformationDto> listItems;
public ObservableCollection<TransactionChartData> ChartData { get; set; }
public ObservableCollection<TransactionInformationDto> TransactionList
{
get { return listItems; }
set { listItems = value; OnPropertyChanged(nameof(TransactionList)); }
}
public ICommand GetTransactions => new Command(async () =>
{
IsBusy = true;
TransactionList.Clear();
var data = await GetAllTransactions();
foreach(var item in data)
{
TransactionList.Add(item);
}
IsBusy = false;
});
public Command<object> ItemTappedCommand
{
get
{
return this.itemTappedCommand ?? (this.itemTappedCommand = new Command<object>(ShowTransactionInformation));
}
}
private void ShowTransactionInformation(object item)
{
var list = item as Syncfusion.ListView.XForms.ItemTappedEventArgs;
var transaction = (TransactionInformationDto)list.ItemData;
Navigation.PushAsync(new TransactionInfoPage(transaction));
}
#endregion
#region Constructor
public DashboardPageViewModel(INavigation navigation)
{
LoadTransactionDetails();
Navigation = navigation;
}
#endregion
#region Properties
public double TotalBalance
{
get
{
return totalBalance;
}
set
{
this.totalBalance = value;
this.OnPropertyChanged();
}
}
public INavigation Navigation { get; }
#endregion
#region Methods
private async Task<ObservableCollection<TransactionInformationDto>> GetAllTransactions()
{
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
return new ObservableCollection<TransactionInformationDto>(await DependencyService.Get<IGetInformation>().GetAllUserTransactions(retrievalInformation));
}
private void LoadTransactionDetails()
{
var userTransactions = new List<TransactionInformationDto>();
Task.Run(async () => {
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
var userBalance = await DependencyService.Get<IGetInformation>().GetUserBalanceInformation(retrievalInformation);
TotalBalance = userBalance.CurrentBalance;
userTransactions = await DependencyService.Get<IGetInformation>().GetTransactionData(retrievalInformation);
});
Thread.Sleep(1000);
WeekData(userTransactions);
}
private void WeekData(List<TransactionInformationDto> transactionInformation)
{
TransactionList = new ObservableCollection<TransactionInformationDto>();
var data = new ObservableCollection<TransactionInformationDto>(transactionInformation.OrderByDescending(x =>x.TimeStamp));
foreach(var item in data)
{
TransactionList.Add(item);
}
days = new string[] { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
ChartData = new ObservableCollection<TransactionChartData>();
UpdateChartData(days);
}
XAML
<Grid Grid.Row="1">
<Label Margin="16,26,16,16"
Text="TRANSACTIONS"
TextColor="{StaticResource Gray-800}"
FontSize="12"
LineHeight="{OnPlatform Android=1.5, Default=-1}"
HorizontalOptions="Start" />
<buttons:SfButton Margin="11,26,11,16"
BorderWidth="0"
TextColor="{StaticResource Gray-600}"
BackgroundColor="{StaticResource Transparent}"
WidthRequest="72"
HeightRequest="18"
Command="{Binding GetTransactions}"
CornerRadius="4"
HorizontalOptions="End">
<Label Text="VIEW ALL"
TextColor="{DynamicResource Link}"
FontSize="12"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
LineHeight="{OnPlatform Android=1.5, Default=-1}"
/>
</buttons:SfButton>
</Grid>
<listView:SfListView Grid.Row="2"
x:Name="_transactionList"
IsScrollBarVisible="False"
ItemSpacing="0"
ItemsSource="{Binding TransactionList}"
SelectionBackgroundColor="{StaticResource TappedBackgroundColor}"
TapCommand="{Binding ItemTappedCommand}"
AutoFitMode="Height"
BackgroundColor="White">
<listView:SfListView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--Profile pic-->
<border:SfBorder Grid.RowSpan="3"
Margin="16"
WidthRequest="40"
HeightRequest="40"
CornerRadius="20"
BorderWidth="0"
VerticalOptions="Center">
<Image Aspect="Fill"
Source="receipt">
</Image>
</border:SfBorder>
<!-- Name -->
<Label Grid.Column="1"
Margin="0,15,0,4"
HorizontalOptions="Start"
Text="{Binding ReceiverName}"
LineHeight="{OnPlatform Android=1.5, Default=-1}" />
<!-- Transaction Title -->
<Label Grid.Row="1"
Grid.Column="1"
Margin="0,0,0,16"
HorizontalOptions="Start"
Text="{Binding TransactionMessage}"
TextColor="{StaticResource Gray-700}"
FontSize="12"
LineHeight="{OnPlatform Android=1.5, Default=-1}" />
<!-- Amount -->
<Label Grid.Column="1"
Margin="0,16,16,4"
HorizontalOptions="End"
TextColor="{Binding IsReceived, Converter={x:StaticResource BooleanToColorConverter}, ConverterParameter=5}"
LineHeight="{OnPlatform Android=1.5, Default=-1}">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding IsReceived, Converter={StaticResource BooleanToStringConverter}, ConverterParameter=2}" />
<Span Text=" $" />
<Span Text="{Binding TransactionAmount}" />
</FormattedString>
</Label.FormattedText>
</Label>
<!-- Date -->
<Label Grid.Row="1"
Grid.Column="1"
Margin="0,0,16,16"
HorizontalOptions="End"
Text="{Binding TimeStamp, StringFormat='{}{0:dd MMM yyyy}'}"
TextColor="{StaticResource Gray-700}"
FontSize="12"
LineHeight="{OnPlatform Android=1.5, Default=-1}" />
<!-- Seperator -->
<BoxView Grid.Row="2" Grid.ColumnSpan="2" Style="{StaticResource SeparatorStyle}" />
</Grid>
</DataTemplate>
</listView:SfListView.ItemTemplate>
</listView:SfListView>
<controls:Popup Grid.Row="2" Grid.RowSpan="1" IsBusy="{Binding IsBusy}" IsEnabled="{Binding IsBusy}" LoadingMessage="Loading the list.." />
</Grid>`
如有任何帮助,我们将不胜感激。
- 永远不要使用 Thread.Sleep()。如果它在 UI 线程上 运行,它会阻止 UI(UI 挂起/不响应)。
1.1。尝试通过添加 Thread.Sleep() 和 Task.Delay() 来解决某些问题是走向地狱的一步。不要输入此路径!
- 您不需要在任何地方都使用 ObservableCollection。如果不需要可观察性,请使用 IList 或 IEnumerable 或数组。
- Task.Run() 创建一个新线程。你通常不需要这个。 + 你在数据绑定方面有问题,因为你需要确保绑定在 UI 线程上执行,以便能够更新 UI 组件。
- 不要在构造函数中加载数据。触发加载和生命周期事件,如 PageAppearing() (https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/app-lifecycle)
更新代码
private ObservableCollection<TransactionInformationDto> listItems;
public ObservableCollection<TransactionChartData> ChartData { get; set; }
public ObservableCollection<TransactionInformationDto> TransactionList
{
get { return listItems; }
set { listItems = value; OnPropertyChanged(nameof(TransactionList)); }
}
public ICommand GetTransactions => new Command(async () =>
{
IsBusy = true;
TransactionList.Clear();
var data = await GetAllTransactions();
TransactionList = new ObservableCollection<TransactionInformationDto>(data);
IsBusy = false;
});
public Command<object> ItemTappedCommand
{
get
{
return this.itemTappedCommand ?? (this.itemTappedCommand = new Command<object>(ShowTransactionInformation));
}
}
private void ShowTransactionInformation(object item)
{
var list = item as Syncfusion.ListView.XForms.ItemTappedEventArgs;
var transaction = (TransactionInformationDto)list.ItemData;
Navigation.PushAsync(new TransactionInfoPage(transaction));
}
#endregion
#region Constructor
public DashboardPageViewModel(INavigation navigation)
{
// LoadTransactionDetails(); // <<< see 4.
Navigation = navigation;
}
#endregion
#region Properties
public double TotalBalance
{
get
{
return totalBalance;
}
set
{
this.totalBalance = value;
this.OnPropertyChanged();
}
}
public INavigation Navigation { get; }
#endregion
#region Methods
private async Task<IEnumerable<TransactionInformationDto>> GetAllTransactions() // see 2.
{
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
return await DependencyService.Get<IGetInformation>().GetAllUserTransactions(retrievalInformation);
}
private async Task LoadTransactionDetails()
{
var userTransactions = new List<TransactionInformationDto>();
// see 3.
var retrievalInformation = await App.Database.GetUserRetrievalInformation();
var userBalance = await DependencyService.Get<IGetInformation>().GetUserBalanceInformation(retrievalInformation);
TotalBalance = userBalance.CurrentBalance;
userTransactions = await DependencyService.Get<IGetInformation>().GetTransactionData(retrievalInformation);
// see. 1. & 1.1.
WeekData(userTransactions);
}
private void WeekData(List<TransactionInformationDto> transactionInformation)
{
TransactionList = new ObservableCollection<TransactionInformationDto>(transactionInformation.OrderByDescending(x =>x.TimeStamp));
days = new string[] { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
ChartData = new ObservableCollection<TransactionChartData>();
UpdateChartData(days);
}
Task.Run 方法将 运行 在尝试更新 UI 的单独线程上。在主线程中添加项目时,布局将更新。 UI 线程被中断,这限制了应用程序中的布局。
https://docs.microsoft.com/en-us/xamarin/ios/user-interface/ios-ui/ui-thread#background-thread-example https://forums.xamarin.com/discussion/comment/96756