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

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无法正确响应集合的新增操作。

修复步骤

  1. 修正属性变更通知的调用:
    在所有属性的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"
            }
        }
    }
    
  2. 优化集合绑定逻辑(可选):
    如果你不会替换整个ObservableCollection实例,只是做Add/Remove等操作,可以直接去掉集合属性的setter,只保留getter。因为ObservableCollection本身会自动触发CollectionChanged事件通知UI刷新,不需要额外触发PropertyChanged:

    public ObservableCollection<PurchasesInvoiceMaster> PurchasesInvoiceMasterObject => _purchasesInvoiceMasterObject;
    
  3. 验证效果:
    修改后,设置ButtonText只会更新按钮文本,不会干扰ListView的集合绑定。ListView会通过ObservableCollection的CollectionChanged事件正常响应元素新增,实现自动刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:21:58