MAUI中ListView绑定ViewModel后添加数据无法刷新的问题
尝试通过XAML将ListView(AllDocuments)绑定到DocumentSummary对象集合,但ListView始终无法刷新:MainPage.xaml.cs的OnButtonClick方法能正常获取数据,每次点击按钮时AllDocuments对象都能正确更新且数据有效,但向AllDocuments添加新项后,ListView并未同步更新,绑定配置存在问题。
当前代码
ViewModel 代码
using CommunityToolkit.Mvvm.Input; using System.Windows.Input; using System.Collections.ObjectModel; using System.Collections.Generic; using System.Diagnostics; namespace peMove.Maui.ViewModels { public class DocumentSummary { public string Id { get; set; } public string Name { get; set; } public string DocType { get; set; } public decimal Onhand { get; set; } public string Note { get; set; } public Color Color { get; set; } } public class DocsViewModel : IQueryAttributable { public ObservableCollection<DocumentSummary> AllDocuments { get; } public DocsViewModel() { this.AllDocuments = new(); this.DocSummary = new(); } public void AddDocument(Document _doc) { //DocSummary = new(); DocSummary.Id = _doc.Id1; DocSummary.Name = _doc.Name; DocSummary.DocType = "Part"; DocSummary.Onhand = _doc.Onhand; DocSummary.Note = "Some note goes here"; DocSummary.Color = MauiProgram.colorPart; this.AllDocuments.Add(DocSummary); Debug.Print(""); } } }
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" xmlns:viewModels="clr-namespace:peMove.Maui.ViewModels" x:Class="peMove.Maui.Pages.MainPage" x:DataType="viewModels:DocsViewModel" Title="Lookup"> <ContentPage.BindingContext> <viewModels:DocsViewModel/> </ContentPage.BindingContext> <VerticalStackLayout Margin="20"> <Button Text="Load" VerticalOptions="Center" HorizontalOptions="Center" Clicked="OnButtonClicked"/> <Entry x:Name="documentId" FontSize="24" Keyboard="Chat" Placeholder="Enter\Scan Id" ClearButtonVisibility="WhileEditing"/> <ListView ItemsSource="{Binding AllDocuments}" HasUnevenRows="True" VerticalOptions="FillAndExpand" SeparatorColor="Black"> <!--<ListView.BindingContext> <viewModels:DocsViewModel/> </ListView.BindingContext>--> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Grid RowDefinitions="Auto" ColumnSpacing="5" ColumnDefinitions="Auto,*,Auto" Margin="10,0"> <!--Column 1--> <Border Grid.Column="0" WidthRequest="40" StrokeShape="RoundRectangle 20,20,20,20" VerticalOptions="Center" HorizontalOptions="Center" BackgroundColor="LightBlue" Padding="12,6" Margin="10" HeightRequest="40"> <Label FontSize="20" Text="{Binding DocSummary.DocType}" TextColor="#FFFFFFDE" VerticalOptions="Center" HorizontalOptions="Center"/> </Border> <!--Column 2--> <VerticalStackLayout Grid.Column="1" Spacing="5" Margin="0,0,0,0"> <Label Text="{Binding DocSummary.Id}" HeightRequest="20" VerticalOptions="Start" HorizontalOptions="Start" FontSize="14" FontAttributes="Bold" TextColor="Black" VerticalTextAlignment="Start"/> <Label Text="{Binding DocSummary.Name}" HeightRequest="20" HorizontalOptions="Start" VerticalOptions="Start" TextColor="{AppThemeBinding Light='#99000000'}" FontSize="16"/> <Label Text="{Binding DocSummary.Note}" HorizontalOptions="Start" VerticalOptions="StartAndExpand" LineBreakMode="WordWrap" TextColor="Black" FontSize="12"/> </VerticalStackLayout> <!--Column 3--> <Label Grid.Column="2" Text="{Binding DocSummary.Onhand, StringFormat='{0:F2}'}" HorizontalOptions="EndAndExpand" VerticalOptions="Start" TextColor="Black" FontSize="18"/> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </VerticalStackLayout> </ContentPage>
MainPage.xaml.cs
using peMove.Maui.Models; using peMove.Maui.ViewModels; using System.Diagnostics; using System.Text; namespace peMove.Maui.Pages { public partial class MainPage : ContentPage { int count = 0; DocsViewModel docs = new(); public MainPage() { InitializeComponent(); //this.BindingContext= docs; } async void OnButtonClicked(object sender, EventArgs args) { DocId key = new DocId(); key.Id1 = "Default"; key.Id2 = "WF201B"; key.Id3 = "000"; ErpPart erpDocument = new(); erpDocument = await ErpPart.LoadAsync(key); // This is working and returning a valid ErpPart. Document _doc = new(); _doc.Id1=erpDocument.Part.Id1; _doc.Name=erpDocument.Part.Name; _doc.DocType = erpDocument.Part.Type; _doc.Onhand=0; _doc.UofM=erpDocument.Part.UofM; _doc.Value01 = erpDocument.Part.Source; _doc.Value02 = erpDocument.Part.Purchased; _doc.Status=erpDocument.Part.Status; docs.AddDocument(_doc); } } }
问题根源及修复方案
1. BindingContext实例不统一
XAML中通过<ContentPage.BindingContext>创建了一个独立的DocsViewModel实例,而MainPage.xaml.cs中又new了另一个docs实例,两者完全独立。修改cs中的docs不会影响XAML绑定的实例,导致界面无反应。
修复:
在MainPage构造函数中设置BindingContext为当前页面的docs实例,移除XAML中的<ContentPage.BindingContext>节点:
public MainPage() { InitializeComponent(); BindingContext = docs; }
2. DataTemplate绑定路径错误
ListView的ItemsSource绑定的是AllDocuments(ObservableCollection<DocumentSummary>),因此每个Item的BindingContext是DocumentSummary对象,但XAML中错误使用{Binding DocSummary.XXX}路径,应该直接绑定DocumentSummary的属性。
修复:
修改ItemTemplate中的绑定路径,并添加x:DataType指定Item类型:
<ListView.ItemTemplate> <DataTemplate x:DataType="viewModels:DocumentSummary"> <ViewCell> <Grid RowDefinitions="Auto" ColumnSpacing="5" ColumnDefinitions="Auto,*,Auto" Margin="10,0"> <!--Column 1--> <Border Grid.Column="0" WidthRequest="40" StrokeShape="RoundRectangle 20,20,20,20" VerticalOptions="Center" HorizontalOptions="Center" BackgroundColor="LightBlue" Padding="12,6" Margin="10" HeightRequest="40"> <Label FontSize="20" Text="{Binding DocType}" TextColor="#FFFFFFDE" VerticalOptions="Center" HorizontalOptions="Center"/> </Border> <!--Column 2--> <VerticalStackLayout Grid.Column="1" Spacing="5" Margin="0,0,0,0"> <Label Text="{Binding Id}" HeightRequest="20" VerticalOptions="Start" HorizontalOptions="Start" FontSize="14" FontAttributes="Bold" TextColor="Black" VerticalTextAlignment="Start"/> <Label Text="{Binding Name}" HeightRequest="20" HorizontalOptions="Start" VerticalOptions="Start" TextColor="{AppThemeBinding Light='#99000000'}" FontSize="16"/> <Label Text="{Binding Note}" HorizontalOptions="Start" VerticalOptions="StartAndExpand" LineBreakMode="WordWrap" TextColor="Black" FontSize="12"/> </VerticalStackLayout> <!--Column 3--> <Label Grid.Column="2" Text="{Binding Onhand, StringFormat='{0:F2}'}" HorizontalOptions="EndAndExpand" VerticalOptions="Start" TextColor="Black" FontSize="18"/> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate>
3. AddDocument方法复用同一个实例
DocsViewModel中DocSummary是类级别的字段,每次调用AddDocument只是修改该实例的属性,再添加到集合中,导致集合中所有项都是同一个对象,既不符合预期也可能引发界面异常。
修复:
每次添加时创建新的DocumentSummary实例:
public void AddDocument(Document _doc) { var docSummary = new DocumentSummary { Id = _doc.Id1, Name = _doc.Name, DocType = "Part", Onhand = _doc.Onhand, Note = "Some note goes here", Color = MauiProgram.colorPart }; AllDocuments.Add(docSummary); }
内容的提问来源于stack exchange,提问作者BumpaRoy

