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

.NET MAUI中ListView无法显示ViewModel的ObservableProperty绑定数据

.NET MAUI MVVM绑定ListView无数据问题

我是.NET MAUI、MVVM、SQLite及C#的新手,尝试通过ViewModel绑定模型类的数据。直接绑定模型命名空间时,ListView能正常显示数据,但切换为ViewModel的ObservableProperty绑定后,数据就不再显示。

可正常工作的CRUDView XAML代码

<Frame Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="3" BackgroundColor="#B1C0C9" BorderColor="#7989A3">
    <ScrollView Orientation="Vertical">
        <ListView x:Name="listView" 
                  BackgroundColor="Gray" 
                  HasUnevenRows="True"
                  SeparatorVisibility="Default"
                  ItemTapped="listView_ItemTapped"
                  FlexLayout.Grow="1">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <VerticalStackLayout Padding="5">
                            <Label Text="{Binding Question}"
                                   FontSize="17" 
                                   FontFamily="OCRA" 
                                   TextColor="Black"/>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="50"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <Label Text="{Binding Id}"
                                       FontSize="10" 
                                       FontFamily="OCRA" 
                                       TextColor="Black"
                                       Grid.Column="0"/>
                                <Label Text="{Binding Answer}"
                                       FontSize="15" 
                                       FontFamily="OCRA" 
                                       TextColor="White"
                                       Grid.Column="1"
                                       Padding="10"/>
                                <Label Text="{Binding Difficulty}"
                                       FontSize="15" 
                                       FontFamily="OCRA" 
                                       TextColor="Black"
                                       Grid.Column="3"
                                       Padding="10"/>
                            </Grid>
                        </VerticalStackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ScrollView>
</Frame>

(原效果:显示数据的ListView)

改用ViewModel绑定后的CRUDView XAML代码

<Frame Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="3" BackgroundColor="#B1C0C9" BorderColor="#7989A3">
    <ScrollView Orientation="Vertical">
        <ListView x:Name="listView" 
                  BackgroundColor="Gray" 
                  HasUnevenRows="True"
                  SeparatorVisibility="Default"
                  ItemTapped="listView_ItemTapped"
                  FlexLayout.Grow="1"
                  ItemsSource="{Binding Flashcards}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="vm:CRUDViewModel">
                    <ViewCell>
                        <VerticalStackLayout Padding="5">
                            <Label Text="{Binding Flashcard.Question}"
                                   FontSize="17" 
                                   FontFamily="OCRA" 
                                   TextColor="Black"/>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="50"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <Label Text="{Binding Flashcard.Id}"
                                       FontSize="10" 
                                       FontFamily="OCRA" 
                                       TextColor="Black"
                                       Grid.Column="0"/>
                                <Label Text="{Binding Flashcard.Answer}"
                                       FontSize="15" 
                                       FontFamily="OCRA" 
                                       TextColor="White"
                                       Grid.Column="1"
                                       Padding="10"/>
                                <Label Text="{Binding Flashcard.Difficulty}"
                                       FontSize="15" 
                                       FontFamily="OCRA" 
                                       TextColor="Black"
                                       Grid.Column="3"
                                       Padding="10"/>
                            </Grid>
                        </VerticalStackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ScrollView>
</Frame>

(原效果:无数据的ListView)

ViewModel代码

namespace cadflash.ViewModels
{
    public partial class CRUDViewModel : ObservableObject
    {
        [ObservableProperty]
        public ObservableCollection<Flashcard> flashcards = new();

        [ObservableProperty]
        public Flashcard flashcard = new();
        
        public CRUDViewModel()
        {
            Flashcard = new Flashcard();
            Flashcards = [];
        }
    }
}

MauiProgram代码

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseMauiCommunityToolkit()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                fonts.AddFont("OCRAEXT.ttf", "OCRA");
            });

        builder.Services.AddSingleton<LocalDbService>();
        builder.Services.AddTransient<HomeView>();
        builder.Services.AddTransient<DifficultyView>();
        builder.Services.AddTransient<CRUDView>();
        builder.Services.AddTransient<CRUDViewModel>();
        builder.Services.AddTransient<DifficultyViewModel>();
        builder.Services.AddTransient<HomeViewModel>();

#if DEBUG
        builder.Logging.AddDebug();
#endif

        return builder.Build();
    }
}

CRUDView.cs代码

public partial class CRUDView : ContentPage
{
    CRUDViewModel viewModel;
    private readonly LocalDbService localDbService;
    private int _editFlashcardId;
    public CRUDView(LocalDbService localDbService)
    {
        InitializeComponent();
        BindingContext = new CRUDViewModel();
        this.localDbService = localDbService;
        Task.Run(async () => await localDbService.GetFlashcardsAsync());
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();
        listView.ItemsSource = await localDbService.GetFlashcardsAsync();
    }
}

问题分析与修复方案

问题出在几个关键节点:

  1. DataTemplate的x:DataType错误:ListView的ItemTemplate上下文是Flashcards集合中的单个Flashcard对象,而非CRUDViewModel,所以x:DataType应指向Flashcard模型。
  2. 绑定路径错误:ItemTemplate的上下文是单个Flashcard,不需要写Flashcard.Question,直接绑定Question即可。
  3. 数据未流入ViewModel:当前OnAppearing直接给控件赋值,绕过了ViewModel的Flashcards集合,应把数据库数据填充到ViewModel中。
  4. 未利用依赖注入:已注册ViewModel,应通过构造函数注入而非手动实例化。

修复步骤:

1. 修改CRUDView的XAML中ItemTemplate部分

<!-- 先在XAML顶部添加Flashcard模型的命名空间,比如 xmlns:model="clr-namespace:cadflash.Models" -->
<ListView.ItemTemplate>
    <DataTemplate x:DataType="model:Flashcard">
        <ViewCell>
            <VerticalStackLayout Padding="5">
                <Label Text="{Binding Question}"
                       FontSize="17" 
                       FontFamily="OCRA" 
                       TextColor="Black"/>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Label Text="{Binding Id}"
                           FontSize="10" 
                           FontFamily="OCRA" 
                           TextColor="Black"
                           Grid.Column="0"/>
                    <Label Text="{Binding Answer}"
                           FontSize="15" 
                           FontFamily="OCRA" 
                           TextColor="White"
                           Grid.Column="1"
                           Padding="10"/>
                    <Label Text="{Binding Difficulty}"
                           FontSize="15" 
                           FontFamily="OCRA" 
                           TextColor="Black"
                           Grid.Column="3"
                           Padding="10"/>
                </Grid>
            </VerticalStackLayout>
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

2. 修改CRUDView.cs,注入ViewModel并更新数据

public partial class CRUDView : ContentPage
{
    private readonly CRUDViewModel viewModel;
    private readonly LocalDbService localDbService;
    private int _editFlashcardId;

    public CRUDView(CRUDViewModel viewModel, LocalDbService localDbService)
    {
        InitializeComponent();
        this.viewModel = viewModel;
        BindingContext = viewModel;
        this.localDbService = localDbService;
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();
        var flashcards = await localDbService.GetFlashcardsAsync();
        viewModel.Flashcards.Clear();
        foreach (var card in flashcards)
        {
            viewModel.Flashcards.Add(card);
        }
    }
}

3. 优化ViewModel构造函数(可选)

public partial class CRUDViewModel : ObservableObject
{
    [ObservableProperty]
    public ObservableCollection<Flashcard> flashcards = new();

    [ObservableProperty]
    public Flashcard flashcard = new();
    
    public CRUDViewModel()
    {
        // ObservableProperty已自动初始化,无需重复赋值
    }
}

修改完成后,ListView即可通过ViewModel正常绑定并显示数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:03:10