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

如何消除C# MAUI ListView的BindingDiagnostics属性未找到警告?

.NET MAUI ListView绑定警告问题排查

问题描述

我是.NET MAUI新手,项目在Windows和Android上能正常运行,可正确显示SQLite数据库中的选民列表,但填充ListView时调试日志会出现绑定警告,希望解决这些问题。

代码与警告信息

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SOTest.MainPage">

    <ScrollView>
            <VerticalStackLayout>

            <Button 
                    Text="Search"
                    Clicked="OnButtonClicked" />

            <ListView 
                x:Name="MyListView"
                ItemsSource="{Binding DataToDisplay}">

                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <VerticalStackLayout Padding="5">
                                    <Label Text="{Binding first_name}" />
                                    <Label Text="{Binding last_name}" />
                                </VerticalStackLayout>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>

                </ListView>

            </VerticalStackLayout>
     </ScrollView>

</ContentPage>

MainPage.xaml.cs

using SQLite;
using System.Diagnostics;
using System.Collections.ObjectModel;

namespace SOTest;

public partial class MainPage : ContentPage
{

    //--- Data Model
    public class MyDataModel
    {
        [PrimaryKey, AutoIncrement]
        public int voter_id { get; set; }
        public string first_name { get; set; }
        public string last_name { get; set; }
        public string street_name { get; set; }
    }



    //--- Database Constants
    public static class DatabaseConstants
    {
        public const string DatabaseFilename = "TestDatabase.db3";

        public const SQLite.SQLiteOpenFlags Flags =
            // open the database in read/write mode
            SQLite.SQLiteOpenFlags.ReadWrite |
            // create the database if it doesn't exist
            SQLite.SQLiteOpenFlags.Create |
            // enable multi-threaded database access
            SQLite.SQLiteOpenFlags.SharedCache;

        public static string DatabasePath =>
            Path.Combine(FileSystem.Current.AppDataDirectory, DatabaseFilename);
    }



    //--- Database Operations
    SQLiteAsyncConnection Database;

    public async Task SetUpDb()
    {
        if (Database is not null)
            return;

        Database = new SQLiteAsyncConnection(DatabaseConstants.DatabasePath, DatabaseConstants.Flags);
        await Database.CreateTableAsync<MyDataModel>();
    }

    public async Task AddRecord(MyDataModel myRecord)
    {
        await SetUpDb();
        await Database.InsertAsync(myRecord);
        Debug.WriteLine($"Inserted {myRecord.first_name} {myRecord.last_name}");
    }

    public async Task<List<MyDataModel>> GetSomeRecords(string LastNameFilter)
    {
        await SetUpDb();
        return await Database.QueryAsync<MyDataModel>("SELECT * FROM [MyDataModel] WHERE [last_name] = '" + LastNameFilter + "' COLLATE NOCASE");
    }

    public async Task<List<MyDataModel>> GetAllRecords()
    {
        await SetUpDb();
        return await Database.Table<MyDataModel>().ToListAsync();
    }



    //--- Observable Collection
    public ObservableCollection<MyDataModel> DataToDisplay { get; set; }



    //--- Main Page and Event Handlers
    public MainPage()
    {
        InitializeComponent();
        DataToDisplay = new ObservableCollection<MyDataModel>() { };
        BindingContext = this;
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();
        await SetUpDb();

        MyDataModel Record1 = new MyDataModel();
        Record1.first_name = "Albert";
        Record1.last_name = "Albertson";
        await AddRecord(Record1);

        MyDataModel Record2 = new MyDataModel();
        Record2.first_name = "Betty";
        Record2.last_name = "Boop";
        await AddRecord(Record2);

        MyDataModel Record3 = new MyDataModel();
        Record3.first_name = "Chris";
        Record3.last_name = "Kringle";
        await AddRecord(Record3);

    }

    //--- Button Click Initiates the Query and ListView Population
    private async void OnButtonClicked(object sender, EventArgs e)
    {
        DataToDisplay.Clear();
        var MyList = await GetAllRecords();
        if (MyList.Count > 0)
        {
            var i = 0;
            foreach (var item in MyList)
            {
                Debug.WriteLine($"Adding {item.first_name}");
                DataToDisplay.Add(item);
                i++;
            }
        }
        else 
        {
            Debug.WriteLine("No Records");
        }

    }

}

运行效果

点击Windows上的“Search”按钮后效果如下:
项目在Windows上的运行效果

警告信息

填充ListView时收到以下警告:

Adding Albert
Adding Betty
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'first_name' property not found on 'SOTest.MainPage', target property: 'Microsoft.Maui.Controls.Label.Text'
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'last_name' property not found on 'SOTest.MainPage', target property: 'Microsoft.Maui.Controls.Label.Text'
Adding Chris
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'first_name' property not found on 'SOTest.MainPage', target property: 'Microsoft.Maui.Controls.Label.Text'
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'last_name' property not found on 'SOTest.MainPage', target property: 'Microsoft.Maui.Controls.Label.Text'
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'first_name' property not found on 'SOTest.MainPage', target property: 'Microsoft.Maui.Controls.Label.Text'
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'last_name' property not found on 'SOTest.MainPage', target property: 'Microsoft.Maui.Controls.Label.Text'

解决方案

问题根源

警告的核心原因是:DataTemplate初始化时,默认会继承外部的BindingContext(也就是MainPage实例),此时ListView还没有加载数据,绑定引擎会尝试在MainPage上查找first_name和last_name属性,自然找不到,从而抛出警告。

解决步骤

有两种简单的方式可以消除这些警告:

方式1:给DataTemplate指定x:DataType

通过明确指定DataTemplate的数据类型,让绑定引擎提前知道要绑定的是MyDataModel对象,而不是外部的MainPage。

修改MainPage.xaml中的DataTemplate部分:

<ListView.ItemTemplate>
    <DataTemplate x:DataType="local:MyDataModel">
        <ViewCell>
            <VerticalStackLayout Padding="5">
                <Label Text="{Binding first_name}" />
                <Label Text="{Binding last_name}" />
            </VerticalStackLayout>
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

同时需要在ContentPage的命名空间中添加local前缀的引用:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SOTest"
             x:Class="SOTest.MainPage">

方式2:在DataTemplate内部显式设置BindingContext

另一种方式是在ViewCell内部手动设置BindingContext为当前列表项:

<ListView.ItemTemplate>
    <DataTemplate>
        <ViewCell BindingContext="{Binding .}">
            <VerticalStackLayout Padding="5">
                <Label Text="{Binding first_name}" />
                <Label Text="{Binding last_name}" />
            </VerticalStackLayout>
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

这种方式通过{Binding .}明确告诉绑定引擎,当前ViewCell的上下文是列表中的单个MyDataModel对象。

额外优化建议

  • 建议将MyDataModel类从MainPage内部移到单独的文件中,符合代码组织规范,也让x:DataType的引用更清晰。
  • 数据库查询中的GetSomeRecords方法存在SQL注入风险,建议改用参数化查询:
public async Task<List<MyDataModel>> GetSomeRecords(string LastNameFilter)
{
    await SetUpDb();
    return await Database.QueryAsync<MyDataModel>("SELECT * FROM [MyDataModel] WHERE [last_name] = ? COLLATE NOCASE", LastNameFilter);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:13:10