You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI中CollectionView无法显示API返回数据的问题排查

.NET MAUI CollectionView 不显示数据排查建议

问题背景

升级到.NET MAUI后,API可正常获取数据,但ObservableCollection中的内容无法在CollectionView中展示。此前用ListView可正常显示,切换后无报错但无内容,API每次返回10条记录(Postman和旧应用验证正常)。

相关代码

XAML 代码

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SaleBeaconMobile.Views.MainPageCus"
             Title="Sale Alerts"
             xmlns:ViewModels="clr-namespace:SaleBeaconMobile.ViewModels">

    <ContentPage.BindingContext>
        <ViewModels:MainPageCusViewModel />
    </ContentPage.BindingContext>

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Debug" Clicked="ToolbarItem_Clicked_3" Order="Secondary" />
        <ToolbarItem Text="Settings" Clicked="ToolbarItem_Clicked"  Order="Secondary"/>
        <ToolbarItem Text="Support" Clicked="ToolbarItem_Clicked_1"  Order="Secondary"/>
        <ToolbarItem Text="Log Out" Clicked="ToolbarItem_Clicked_2"  Order="Secondary"/>
    </ContentPage.ToolbarItems>

    <ContentPage.Content>
        <RefreshView>
            <CollectionView x:Name="CVSaleAlerts"
                    ItemsSource="{Binding Items}"
                    ItemsLayout="VerticalList"
                    RemainingItemsThreshold="4"
                    RemainingItemsThresholdReachedCommand="{Binding LoadMoreItemsCommand}"
                    HeightRequest="300">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Grid Padding="10">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="280" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="350" />
                            </Grid.ColumnDefinitions>
                            <Image Source="{Binding bg}"
                           Grid.Row="0"
                           Grid.Column="0"
                           Aspect="AspectFill"
                           WidthRequest="350"
                           HeightRequest="280"
                           MinimumHeightRequest="280"
                           VerticalOptions="FillAndExpand" />
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </RefreshView>
    </ContentPage.Content>
</ContentPage>

ViewModel 代码

using SaleBeaconMobile.Models;
using SaleBeaconMobile.Services;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.Maui.Controls.Xaml;

namespace SaleBeaconMobile.ViewModels
{
    public class MainPageCusViewModel : BaseViewModel
    {
        private readonly DataService _dataService = new DataService();
        private const int PageSize = 10;
        private int _currentPage = 0; // Track the current page for loading more data

        public ObservableCollection<Sale> Items { get; }

        private bool _isRefreshing;
        public bool IsRefreshing
        {
            get => _isRefreshing;
            set
            {
                _isRefreshing = value;
                OnPropertyChanged();
            }
        }

        public ICommand LoadMoreItemsCommand { get; }

        public ICommand RefreshCommand => new Command(async () => await DownloadDataAsync());

        public MainPageCusViewModel()
        {
            Items = new ObservableCollection<Sale>();

            // Assign the command to LoadMoreItemsCommand
            LoadMoreItemsCommand = new Command(async () => await LoadMoreItemsAsync());

            // Trigger initial data load
            Task.Run(async () => await DownloadDataAsync());
        }

        // Method to load initial data
        public async Task DownloadDataAsync()
        {
            try
            {
                IsRefreshing = true;

                // Fetch initial data (page 0 or starting page)
                var items = await _dataService.GetItemsAsync(0, PageSize);

                // Clear existing items and add new items
                Items.Clear();

                foreach (var item in items)
                {
                    Items.Add(item);
                }

                // Update the current page
                _currentPage = 1; // Assuming pages start from 0
            }
            catch (Exception ex)
            {
                // Handle exceptions as needed
            }
            finally
            {
                IsRefreshing = false;
            }
        }

        // Method to load more items for pagination or infinite scrolling
        public async Task LoadMoreItemsAsync()
        {
            try
            {
                if (IsRefreshing)
                    return; // Prevent re-entry

                IsRefreshing = true;

                // Fetch more data based on the current page
                var items = await _dataService.GetItemsAsync(_currentPage, PageSize);

                // Add new items to the existing collection
                foreach (var item in items)
                {
                    Items.Add(item);
                }

                // Increment the current page for the next load
                _currentPage++;
            }
            catch (Exception ex)
            {
                // Handle exceptions as needed
            }
            finally
            {
                IsRefreshing = false;
            }
        }
    }
}

排查步骤

1. 补全RefreshView的绑定属性

你的RefreshView未绑定Command和IsRefreshing,这会导致刷新状态无法同步,甚至影响CollectionView的布局更新。修改XAML中的RefreshView:

<RefreshView Command="{Binding RefreshCommand}" IsRefreshing="{Binding IsRefreshing}">
    <!-- 原CollectionView内容 -->
</RefreshView>

2. 移除CollectionView的固定高度约束

你给CollectionView设置了HeightRequest="300",如果数据项总高度超出这个值,或者数据加载时布局计算异常,会导致内容无法显示。建议移除固定高度,让控件自适应父布局:

<CollectionView x:Name="CVSaleAlerts"
                ItemsSource="{Binding Items}"
                ItemsLayout="VerticalList"
                RemainingItemsThreshold="4"
                RemainingItemsThresholdReachedCommand="{Binding LoadMoreItemsCommand}">
    <!-- 原ItemTemplate内容 -->
</CollectionView>

同时确保ContentPage的Content布局设置为VerticalOptions="FillAndExpand",让CollectionView能占满可用空间。

3. 验证数据绑定和集合状态

  • 确认BaseViewModel正确实现INotifyPropertyChanged接口,确保绑定上下文的变更能通知到UI。
  • 在DownloadDataAsync方法中添加调试日志,确认数据已正确加入集合:
    foreach (var item in items)
    {
        Items.Add(item);
        System.Diagnostics.Debug.WriteLine($"Added item: {item.bg}, total items in collection: {Items.Count}");
    }
    
    查看输出面板,确认集合数量是否正确。

4. 测试DataTemplate的绑定有效性

暂时在DataTemplate中添加一个Label,验证数据项的绑定是否生效:

<DataTemplate>
    <Grid Padding="10">
        <Image Source="{Binding bg}"
               Grid.Row="0"
               Grid.Column="0"
               Aspect="AspectFill"
               WidthRequest="350"
               HeightRequest="280"
               MinimumHeightRequest="280"
               VerticalOptions="FillAndExpand" />
        <Label Text="{Binding bg}" Grid.Row="0" Grid.Column="0" TextColor="Red" FontSize="Large"/>
    </Grid>
</DataTemplate>

如果Label能显示内容,说明绑定没问题,问题可能出在Image的Source加载(比如bg不是有效的图片路径/资源名);如果Label也不显示,说明数据项的绑定存在问题,检查Sale类的bg属性是否为公共可访问的。

5. 修正初始数据加载的线程方式

ViewModel构造函数中使用Task.Run(async () => await DownloadDataAsync())可能导致UI线程上下文异常,建议改为直接调用:

// 替换原Task.Run代码
_ = DownloadDataAsync();

或者在页面的OnAppearing方法中触发加载,确保在UI线程上下文执行:

// 在MainPageCus.xaml.cs中添加
protected override async void OnAppearing()
{
    base.OnAppearing();
    if (BindingContext is MainPageCusViewModel vm)
    {
        await vm.DownloadDataAsync();
    }
}

6. 暂时禁用分页相关属性

先移除RemainingItemsThreshold和RemainingItemsThresholdReachedCommand,排除分页逻辑对初始数据显示的干扰,确认初始数据能正常显示后再恢复分页功能。


内容的提问来源于stack exchange,提问作者Joey007

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:25:55