MAUI中ListView无法自动刷新问题求助
测试应用包含两个数据绑定元素:Button和ListView。当前ListView无法自动刷新,但禁用ViewModel中ButtonText = $"It took {totalSecs} seconds"这段代码后,ListView就能正常自动刷新。求解决思路。
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:local="clr-namespace:test" x:Class="test.MainPage"> <ContentPage.BindingContext> <local:PurchasesInvoiceMasterViewModel /> </ContentPage.BindingContext> <ScrollView> <VerticalStackLayout Spacing="25" Padding="30,0" VerticalOptions="Start"> <Button x:Name="PurchasesInvoiceList" Text="{Binding ButtonText}" Command="{Binding AddListCommand}" SemanticProperties.Hint="Get Purchases Invoice List" HorizontalOptions="Center" /> <ListView x:Name="PurchasesInvoiceMasterObjectView" ItemsSource="{Binding PurchasesInvoiceMasterObject}" HeightRequest="500"> <ListView.ItemTemplate> <DataTemplate> <TextCell Text="{Binding purchases_invoice_id}" Detail="{Binding purchases_invoice_date }" /> </DataTemplate> </ListView.ItemTemplate> </ListView> </VerticalStackLayout> </ScrollView> </ContentPage>
ViewModel代码
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows.Input; using System.Xml.Linq; namespace test { class PurchasesInvoiceMasterViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public ICommand AddListCommand { get; set; } private string _buttonText = "Purchases Invoice List"; public string ButtonText { get => _buttonText; set { if (_buttonText != value) { _buttonText = value; OnPropertyChanged(""); } } } private ObservableCollection<PurchasesInvoiceMaster> _purchasesInvoiceMasterObject = new(); public ObservableCollection<PurchasesInvoiceMaster> PurchasesInvoiceMasterObject { get => _purchasesInvoiceMasterObject; set { if (_purchasesInvoiceMasterObject != value) { _purchasesInvoiceMasterObject = value; OnPropertyChanged(""); } } } public PurchasesInvoiceMasterViewModel() { AddListCommand = new Command(() => { double statrtSecs = DateTime.Now.TimeOfDay.TotalSeconds; string purchasesInvoiceMaster = "test.PurchasesInvoiceMaster.xml"; using (Stream streamPurchasesInvoiceMaster = this.GetType().Assembly.GetManifestResourceStream(purchasesInvoiceMaster)) { using (var readerPurchasesInvoiceMaster = new System.IO.StreamReader(streamPurchasesInvoiceMaster)) { var xmlpurchasesInvoiceMaster = XDocument.Load(readerPurchasesInvoiceMaster); foreach (XElement xmmd in xmlpurchasesInvoiceMaster.Descendants("curtemp01")) { _purchasesInvoiceMasterObject.Add(new PurchasesInvoiceMaster { purchases_invoice_id = xmmd.Element("purchases_invoice_id").Value, purchases_invoice_date = xmmd.Element("purchases_invoice_date").Value, }); } } } double endSecs = DateTime.Now.TimeOfDay.TotalSeconds; float totalSecs = (float)(endSecs - statrtSecs); ButtonText = $"It took {totalSecs} seconds"; }); } public void OnPropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } }
问题根源与解决思路
问题原因
核心问题出在OnPropertyChanged("")的调用上:传入空字符串会触发ViewModel所有属性的变更通知。当你设置ButtonText时,会连带触发PurchasesInvoiceMasterObject的属性变更,导致ListView重新绑定ItemsSource。而此时你是直接往ObservableCollection实例中添加元素,ObservableCollection本身的CollectionChanged事件已经能通知UI刷新,但全属性变更通知会干扰这个过程,导致ListView无法正确响应集合的新增操作。
修复步骤
修正属性变更通知的调用:
在所有属性的setter中,不要传入空字符串,而是利用[CallerMemberName]特性自动获取当前属性名,直接调用OnPropertyChanged()即可。这样只会触发当前属性的变更通知,不会影响其他绑定。修改后的
ButtonText属性:public string ButtonText { get => _buttonText; set { if (_buttonText != value) { _buttonText = value; OnPropertyChanged(); // 自动传入"ButtonText" } } }修改后的
PurchasesInvoiceMasterObject属性:public ObservableCollection<PurchasesInvoiceMaster> PurchasesInvoiceMasterObject { get => _purchasesInvoiceMasterObject; set { if (_purchasesInvoiceMasterObject != value) { _purchasesInvoiceMasterObject = value; OnPropertyChanged(); // 自动传入"PurchasesInvoiceMasterObject" } } }优化集合绑定逻辑(可选):
如果你不会替换整个ObservableCollection实例,只是做Add/Remove等操作,可以直接去掉集合属性的setter,只保留getter。因为ObservableCollection本身会自动触发CollectionChanged事件通知UI刷新,不需要额外触发PropertyChanged:public ObservableCollection<PurchasesInvoiceMaster> PurchasesInvoiceMasterObject => _purchasesInvoiceMasterObject;验证效果:
修改后,设置ButtonText只会更新按钮文本,不会干扰ListView的集合绑定。ListView会通过ObservableCollection的CollectionChanged事件正常响应元素新增,实现自动刷新。
内容的提问来源于stack exchange,提问作者WWW

