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

Xamarin.Forms中更新CollectionView时维持滚动位置的实现方案

Xamarin.Forms CollectionView 定时更新时保持滚动位置的解决方案

问题根源

当前每次更新数据时直接创建新的ObservableCollection并赋值给Lista_Mesas,这会导致CollectionView完全重新绑定数据源,从而丢失之前的滚动位置。


解决方案

1. 复用现有ObservableCollection,避免替换整个集合

初始化时创建一次集合实例,后续更新仅修改集合内的元素(新增、删除、更新属性),让CollectionView只渲染变化的部分,维持滚动位置。

修改ViewModel构造函数

public MesasAbiertasViewModels(INavigation nav)
{
    Navigation = nav;

    ds_ma = new DataServiceMesasAbiertas();
    _dspedidos = new DataServicePedidosView();
    ds_abrir_mesa = new DataServiceAbrirMesaView();
    _dspda = new DataServiceConfigurarPDA();

    list_config = _dspda.ObtenerTodosConfiguracion();
    // 初始化集合,后续复用该实例
    Lista_Mesas = new ObservableCollection<CabeceraComandaModels>();
    IniciarActualizacion();
}

修改CargarListaMesas方法

public async void CargarListaMesas()
{
    try
    {
        // 获取最新数据
        var nuevasMesas = ds_ma.ObtenerComandasCab().ToList();
        mesas_ocupadas = ds_ma.ObtenerMesasAbiertas();

        // 回到UI线程更新集合(集合操作必须在UI线程执行)
        await Device.InvokeOnMainThreadAsync(() =>
        {
            // 移除不在新数据中的旧项
            var itemsToRemove = Lista_Mesas.Where(item => !nuevasMesas.Any(n => n.Id_comanda == item.Id_comanda)).ToList();
            foreach (var item in itemsToRemove)
            {
                Lista_Mesas.Remove(item);
            }

            // 更新或添加新项
            foreach (var nuevaMesa in nuevasMesas)
            {
                bool ocupada = MesaOcupada(nuevaMesa.Mesa, mesas_ocupadas);
                nuevaMesa.Total = nuevaMesa.Total_condto > 0 ? nuevaMesa.Total_condto : nuevaMesa.Total_coniva;
                nuevaMesa.Esta_abierta = ocupada ? 1 : 0;

                var existingItem = Lista_Mesas.FirstOrDefault(item => item.Id_comanda == nuevaMesa.Id_comanda);
                if (existingItem != null)
                {
                    // 更新现有项的属性
                    existingItem.Mesa = nuevaMesa.Mesa;
                    existingItem.Total = nuevaMesa.Total;
                    existingItem.Esta_abierta = nuevaMesa.Esta_abierta;
                    existingItem.Comprobante = nuevaMesa.Comprobante;
                    // 补充其他需要更新的属性
                }
                else
                {
                    // 添加新项到集合
                    Lista_Mesas.Add(nuevaMesa);
                }
            }
        });
    }
    catch(Exception mi)
    {
        await DisplayAlert("Error", mi.Message, "OK");
    }
}

2. 确保数据模型实现INotifyPropertyChanged

CabeceraComandaModels需要实现接口,让属性更新时自动通知UI刷新,避免重新创建项:

public class CabeceraComandaModels : INotifyPropertyChanged
{
    private int _mesa;
    public int Mesa
    {
        get => _mesa;
        set
        {
            _mesa = value;
            OnPropertyChanged();
        }
    }

    private decimal _total;
    public decimal Total
    {
        get => _total;
        set
        {
            _total = value;
            OnPropertyChanged();
        }
    }

    private int _esta_abierta;
    public int Esta_abierta
    {
        get => _esta_abierta;
        set
        {
            _esta_abierta = value;
            OnPropertyChanged();
        }
    }

    // 其他属性同理实现

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

3. 特殊场景:必须替换集合时恢复滚动位置

如果业务上必须替换整个集合,可以先记录滚动位置,替换后恢复:

在View的代码-behind中添加逻辑

private double _lastScrollY;

// 监听滚动事件记录位置
private void lstpedidos_Scrolled(object sender, ItemsViewScrolledEventArgs e)
{
    _lastScrollY = e.VerticalOffset;
}

// 恢复滚动位置的方法
public async Task RestoreScrollPosition()
{
    if (lstpedidos.ItemsLayout is LinearItemsLayout)
    {
        await lstpedidos.ScrollToAsync(_lastScrollY, ScrollToPosition.Start, animate: false);
    }
}

可通过MessagingCenter或绑定命令,在ViewModel更新集合后通知View调用恢复方法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:02:33