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>`

如有任何帮助,我们将不胜感激。

  1. 永远不要使用 Thread.Sleep()。如果它在 UI 线程上 运行,它会阻止 UI(UI 挂起/不响应)。

1.1。尝试通过添加 Thread.Sleep() 和 Task.Delay() 来解决某些问题是走向地狱的一步。不要输入此路径!

  1. 您不需要在任何地方都使用 ObservableCollection。如果不需要可观察性,请使用 IList 或 IEnumerable 或数组。
  2. Task.Run() 创建一个新线程。你通常不需要这个。 + 你在数据绑定方面有问题,因为你需要确保绑定在 UI 线程上执行,以便能够更新 UI 组件。
  3. 不要在构造函数中加载数据。触发加载和生命周期事件,如 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