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

.NET MAUI发布版CollectionView项不显示问题排查

.NET MAUI CollectionView发布版显示空白项问题

问题场景

使用Visual Studio开发的小型.NET MAUI应用,从API下载包含10个球员信息的JSON并加载到CollectionView中:

  • IDE内调试时:CollectionView正常显示球员ID、姓名等信息,Editor能展示JSON内容
  • 调试文件夹运行程序时:Editor正常显示JSON,但CollectionView仅显示10个空白项(有轮廓无内容)

相关代码

ViewModel代码

public partial class PlayerListViewModel: ObservableObject {

    [ObservableProperty]
    public string text = "";

    public PlayerListViewModel() {
        PlayerListItems = new ObservableCollection < Player > ();
    }

    [ObservableProperty]
    ObservableCollection < Player > playerListItems;

    [RelayCommand]
    public void View() {

    }

    [RelayCommand]
    async Task getPlayersAPI() {

        HttpClient _httpClient = new HttpClient();
        string _url = "https://mywebsite.com/all-players.php";

        var response = await _httpClient.GetAsync(_url);
        var responseString = await response.Content.ReadAsStringAsync();
        var playerListItems = JsonSerializer.Deserialize < List < Player >> (responseString);

        Text = responseString.ToString();

        PlayerListItems.Clear();
        foreach(var item in playerListItems) {
            PlayerListItems.Add(item);
        }

    }

}

Player实体类

public class Player {
    public int Id {
        get;
        set;
    }
    public required string fullName {
        get;
        set;
    }
    public required string imageSrc {
        get;
        set;
    }
    public required string countryFlag {
        get;
        set;
    }

}

JSON示例

[
  {
    "Id": 577,
    "fullName": "Bob Smith",
    "imageSrc": "ProfileImage.webp",
    "countryFlag": "us.svg"
  },
  {
    "Id": 744,
    "fullName": "George Kingford",
    "imageSrc": "ProfileImage.webp",
    "countryFlag": "ca.svg"
  }
]

XAML代码

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyProject.PlayerList"
             Title="PlayerList"
             xmlns:viewmodel="clr-namespace:MyProject.ViewModel"
             x:DataType="viewmodel:PlayerListViewModel">


        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="100"></RowDefinition>
                <RowDefinition Height="200"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
                <RowDefinition Height="50"></RowDefinition>
        </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="300"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>


            <Button x:Name="getBtn" Text="Load" Command="{Binding getPlayersAPICommand}" Margin="10" HeightRequest="30" Grid.Column="1"></Button>
            <Editor x:Name="testData" Text="{Binding Text}" Margin="10" Grid.Column="1" Grid.Row="1"></Editor>

            <ScrollView Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" VerticalOptions="End" VerticalScrollBarVisibility="Always"  >

            <CollectionView ItemsSource="{Binding PlayerListItems}" EmptyView="No players downlaoded" SelectionMode="Single" >
                <CollectionView.Header>
                    <VerticalStackLayout>
                        <Label Text="Players" HorizontalOptions="Center" FontAttributes="Bold" FontSize="18"></Label>
                    </VerticalStackLayout>
                </CollectionView.Header>
                <CollectionView.ItemTemplate>
                    <DataTemplate x:DataType="{x:Type viewmodel:PlayerListViewModel}">
                        <SwipeView>
                            <SwipeView.RightItems>
                                <SwipeItem Text="Edit" BackgroundColor="Green" />
                            </SwipeView.RightItems>

                            <Grid Padding="10">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="50"></ColumnDefinition>
                                    <ColumnDefinition Width="auto"></ColumnDefinition>
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="50*"></RowDefinition>
                                    <RowDefinition Height="50*"></RowDefinition>
                                </Grid.RowDefinitions>
                                <Image Grid.Column="0" Grid.Row="0" Grid.RowSpan="1" HeightRequest="30" Source="{Binding Source, Source={x:Reference countryFlag}}"></Image>
                                    <Label Grid.Column="1" Grid.Row="0" Text="{Binding fullName}" FontAttributes="Bold" ></Label >
                                <HorizontalStackLayout Grid.Column="1" Grid.Row="1">
                                    <Label Text="ID: "></Label >
                                    <Label TextColor="Black" Text="{Binding Id}" ></Label >
                                </HorizontalStackLayout>
                            </Grid>

                        </SwipeView>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
               
            </CollectionView>
            </ScrollView>

         </Grid>

</ContentPage>

解决方案

1. 修正DataTemplate的x:DataType

这是核心问题:调试模式下XAML绑定有容错机制,发布版启用编译时绑定检查,错误的DataType会直接导致绑定失效。

  • 先在ContentPage的命名空间中添加Player实体所在的命名空间(假设实体在MyProject.Models下):
    xmlns:model="clr-namespace:MyProject.Models"
    
  • 修改ItemTemplate的DataType为Player实体:
    <DataTemplate x:DataType="{x:Type model:Player}">
    

2. 修正Image控件的绑定逻辑

原代码中Image的绑定写法错误,应直接绑定到Player实体的countryFlag属性,同时调整布局的RowSpan让图片显示更合理:

<Image Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" HeightRequest="30" Source="{Binding countryFlag}"></Image>

3. 优化JSON序列化配置

默认序列化器对大小写敏感,显式配置忽略大小写可避免潜在的字段匹配问题:
在ViewModel的getPlayersAPI方法中修改反序列化代码:

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};
var playerListItems = JsonSerializer.Deserialize<List<Player>>(responseString, options);

4. 确保UI操作在主线程执行

虽然ObservableCollection的变更会自动通知UI,但非主线程操作可能引发异常或显示问题,将添加项的代码包裹在主线程调用中:

MainThread.BeginInvokeOnMainThread(() =>
{
    PlayerListItems.Clear();
    foreach(var item in playerListItems)
    {
        PlayerListItems.Add(item);
    }
});

5. 优化HttpClient实例创建

避免每次请求都创建新的HttpClient,改用静态单例模式:

private static readonly HttpClient _httpClient = new HttpClient();

[RelayCommand]
async Task getPlayersAPI() {
    string _url = "https://mywebsite.com/all-players.php";
    // 其余逻辑保持不变
}

完成以上修改后,重新编译发布版本,CollectionView即可正常显示所有球员信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:28:09