Xamarin.Forms ListView持续创建ViewCells绑定同一ViewModel问题求助
问题描述
我编写了一个Xamarin.Forms的Demo,发现ListView会持续创建ViewCell,并且全部绑定到同一个ViewModel,最终会耗尽内存。运行后界面中的Cell Serial #和Pings数值会持续增长,即使列表只有一项也是如此;添加两项后,两个单元格的这两个数值也会不断增长。
相关代码
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="LVD.MainPage"> <StackLayout> <Label Text="This is a listview with one item."/> <Label Text="{Binding MainNum}"/> <ListView x:Name="DemoList" ItemsSource="{Binding Itms}" RowHeight="75" CachingStrategy="RecycleElement"> </ListView> </StackLayout> </ContentPage>
MainPage.xaml.cs
public partial class MainPage : ContentPage { MainVM _vm = null; public MainPage() { InitializeComponent(); _vm = new MainVM(); BindingContext = _vm; DemoList.ItemTemplate = new DataTemplate(typeof(myCell)); } }
MainVM.cs
using System.Collections.ObjectModel; namespace LVD { class MainVM { public string MainNum { get; set; } private static int _mainserno = 0; public ObservableCollection<CellVM> Itms { get; set; } public MainVM() { MainNum = "Parent serial#: " + _mainserno.ToString(); _mainserno++; if (Itms == null) Itms = new ObservableCollection<CellVM>(); else Itms.Clear(); CellVM item = new CellVM(); Itms.Add(item); //CellVM item2 = new CellVM(); //Itms.Add(item2); } } }
myCell.cs
using Xamarin.Forms; namespace LVD { class myCell : ViewCell { static int _localserialno = 0; Label VMnumLbl, CellNumLbl, PLbl; public static readonly BindableProperty ItemProperty = BindableProperty.Create("CellItem", typeof(CellVM), typeof(myCell), null); public CellVM CellItem { get { return (CellVM)GetValue(ItemProperty); } set { SetValue(ItemProperty, value); } } public myCell() { VMnumLbl = new Label(); VMnumLbl.SetBinding(Label.TextProperty, "VMSerNum", BindingMode.Default, null, "VM Serial #: {0}"); CellNumLbl = new Label(); CellNumLbl.SetBinding(Label.TextProperty, "CellSerNum", BindingMode.Default, null, "Cell Serial #: {0}"); PLbl = new Label(); PLbl.SetBinding(Label.TextProperty, "PingCount", BindingMode.Default, null, "Pings: {0}"); var stackit = new StackLayout(); stackit.Children.Add(VMnumLbl); stackit.Children.Add(CellNumLbl); stackit.Children.Add(PLbl); View = stackit; } protected override void OnBindingContextChanged() { base.OnBindingContextChanged(); if (BindingContext == null) CellItem = null; else if (BindingContext != CellItem) { CellItem = (CellVM)BindingContext; CellItem.CellSerNum = _localserialno++; CellItem.Ping(); } } } }
CellVM.cs
class CellVM : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } private static int serialno = 0; private int _vmserialno; public int VMSerNum { get { return _vmserialno; } } public int CellSerNum { get; set; } public int PingCount { get; set; } public CellVM() { _vmserialno = serialno++; PingCount = 0; } public void Ping() { PingCount++; OnPropertyChanged(string.Empty); } }
运行现象
This is a listview with one item. Parent serial #: 0 VM Serial #: 0 Cell Serial #: ++ Pings: ++
Cell Serial #和Pings数值持续增长。
问题原因及解决方法
核心原因
无限循环触发绑定上下文变更:
- 在
myCell.OnBindingContextChanged中,设置CellSerNum并调用Ping(); Ping()里调用OnPropertyChanged(string.Empty),这会触发ViewModel所有属性的变更通知,包括刚设置的CellSerNum;- 属性变更会让ListView认为单元格需要更新,重新设置BindingContext,再次触发
OnBindingContextChanged; - 循环往复,导致
CellSerNum和PingCount持续增长,ViewCell被反复绑定。
解决步骤
- 修改
Ping()方法的属性通知:只触发PingCount的变更,而非所有属性
public void Ping() { PingCount++; OnPropertyChanged(nameof(PingCount)); }
- 调整
CellSerNum的设置位置:将其移到CellVM的构造函数中,避免在绑定上下文变更时重复赋值
class CellVM : INotifyPropertyChanged { // 添加静态计数器 private static int _cellSerCounter = 0; // ... 其他代码 public CellVM() { _vmserialno = serialno++; PingCount = 0; CellSerNum = _cellSerCounter++; // 在这里设置单元格序列号 } // ... 其他代码 }
- 移除
myCell.OnBindingContextChanged中的冗余代码:删除CellItem.CellSerNum = _localserialno++;这一行
经过以上修改,即可打破无限循环,ViewCell不会被反复创建和绑定,数值也不会持续增长。
内容的提问来源于stack exchange,提问作者Karen Cate
相关产品推荐
相关产品推荐

