MAUI ListView在Android滚动时崩溃异常,求助排查问题
基于MAUI开发Android应用原型时,ListView组件出现异常:当列表项数量超出屏幕需快速滚动时应用崩溃,底层Android错误为java.lang.IllegalStateException: The specified child already has a parent,缓慢滚动则无此问题。
尝试将ListView的CachingStrategy设置为"RecycleElementAndDataTemplate"可解决崩溃,但会导致单选按钮滚动出视图后丢失选中状态,还存在列表项文本消失等问题。
相关代码
ListView XAML代码
<ListView ItemsSource="{Binding Devices}" Style="{StaticResource ListViewSimpleStyle}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell x:DataType="local:DeviceEntryModel"> <RadioButton IsChecked="{Binding IsChecked, Mode=TwoWay}" GroupName="Devices"> <RadioButton.Content> <Label BindingContext="{Binding Source={RelativeSource AncestorType={x:Type RadioButton}}, Path=BindingContext}" Text="{Binding Name}" IsEnabled="{Binding Source={RelativeSource AncestorType={x:Type RadioButton}}, Path=IsEnabled}" /> </RadioButton.Content> </RadioButton> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
模型类代码
public partial class DeviceEntryModel : ObservableObject { public DeviceEntry DeviceEntry { get; init; } public string Name => DeviceEntry.Name; public string Address => DeviceEntry.Address; [ObservableProperty] bool isChecked; }
核心问题
崩溃的根源在于Label手动设置BindingContext的方式引发视图复用冲突:
- RadioButton的Content区域默认继承RadioButton的BindingContext(即
DeviceEntryModel),额外通过RelativeSource手动指定Label的BindingContext属于冗余操作。 - 当ListView快速滚动触发视图复用(即使默认缓存策略)时,这种冗余绑定会导致Label控件被错误地重复关联到不同的父容器,触发Android底层的
The specified child already has a parent异常。
而设置RecycleElementAndDataTemplate后出现的选中状态丢失、文本消失问题,是因为视图复用过程中,错误的绑定逻辑导致控件无法正确从模型同步最新状态。
修复步骤
1. 简化Label的绑定逻辑
删除Label上冗余的BindingContext设置,直接利用继承的上下文绑定数据:
<ListView ItemsSource="{Binding Devices}" Style="{StaticResource ListViewSimpleStyle}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell x:DataType="local:DeviceEntryModel"> <RadioButton IsChecked="{Binding IsChecked, Mode=TwoWay}" GroupName="Devices"> <RadioButton.Content> <!-- 移除手动设置的BindingContext,直接继承RadioButton的上下文 --> <Label Text="{Binding Name}" IsEnabled="{Binding Source={RelativeSource AncestorType={x:Type RadioButton}}, Path=IsEnabled}" /> </RadioButton.Content> </RadioButton> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
2. 恢复默认缓存策略(或使用RecycleElement)
移除CachingStrategy="RecycleElementAndDataTemplate"设置,使用ListView默认的缓存策略即可。若需优化性能,可设置为CachingStrategy="RecycleElement"——此时因为绑定逻辑已修复,视图复用会正确同步模型的IsChecked状态,不会出现选中状态丢失问题。
3. 确认数据源类型正确性
确保Devices是ObservableCollection<DeviceEntryModel>类型(而非ObservableCollection<DeviceEntry>),保证每个列表项的上下文都是DeviceEntryModel,绑定才能正常生效。
内容的提问来源于stack exchange,提问作者something5143

