.NET MAUI ListView内部元素获焦时SelectedItem未自动设置的问题
解决.NET MAUI ListView内部控件获焦时自动设置SelectedItem的问题
这个问题我之前也碰到过——默认情况下,ListView的SelectedItem只有在点击Item的空白区域时才会更新,ItemTemplate里的控件(比如Entry、Button)获得焦点并不会自动触发选中状态。下面给你两种可行的解决方案,按需选择:
方法1:使用Behavior(MVVM友好推荐)
这种方式将选中逻辑封装成可复用的Behavior,适合MVVM架构,不需要在页面后台写过多代码。
首先创建一个自定义Behavior类:
using Microsoft.Maui.Controls; namespace YourProjectNamespace; // 替换成你的项目命名空间 public class SelectListViewItemOnFocusBehavior : Behavior<VisualElement> { protected override void OnAttachedTo(VisualElement bindable) { base.OnAttachedTo(bindable); bindable.Focused += OnControlFocused; } protected override void OnDetachingFrom(VisualElement bindable) { base.OnDetachingFrom(bindable); bindable.Focused -= OnControlFocused; } private void OnControlFocused(object sender, FocusEventArgs e) { // 递归查找当前控件所在的ViewCell var viewCell = FindParent<ViewCell>(sender as VisualElement); if (viewCell == null) return; // 查找对应的ListView var listView = FindParent<ListView>(viewCell); if (listView == null) return; // 将SelectedItem设置为当前项的BindingContext(即列表中的数据模型) listView.SelectedItem = viewCell.BindingContext; } // 通用的父控件查找方法 private T FindParent<T>(VisualElement element) where T : VisualElement { var parent = element.Parent as VisualElement; while (parent != null) { if (parent is T typedParent) return typedParent; parent = parent.Parent as VisualElement; } return null; } }
接下来在XAML中给需要触发选中的控件附加这个Behavior,记得先引入命名空间:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:YourProjectNamespace" <!-- 替换成你的命名空间 --> x:Class="YourProjectNamespace.YourPage"> <!-- 你的其他布局代码 --> <ListView x:Name="LstMedios" Grid.Row="2" ItemsSource="{Binding MediosDePago}" SelectedItem="{Binding MedioPagoSeleccionado,Mode=TwoWay}" SelectionMode="Single"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Grid ColumnDefinitions="2*,*" > <Button Text="My button" HeightRequest="40" HorizontalOptions="FillAndExpand" Margin="5,5" > <Button.Behaviors> <local:SelectListViewItemOnFocusBehavior /> </Button.Behaviors> </Button> <Entry Text="{Binding NumValor,StringFormat='{0:c}'}" Keyboard="Numeric" Grid.Column="1" HorizontalTextAlignment="End" Margin="0,5,5,5"> <Entry.Behaviors> <local:SelectListViewItemOnFocusBehavior /> </Entry.Behaviors> </Entry> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage>
方法2:直接在控件Focused事件中处理(代码后台方式)
如果你的项目没有严格遵循MVVM,或者更倾向于在页面后台处理逻辑,可以直接给控件添加Focused事件:
首先修改XAML,给Button和Entry添加事件绑定:
<ListView x:Name="LstMedios" Grid.Row="2" ItemsSource="{Binding MediosDePago}" SelectedItem="{Binding MedioPagoSeleccionado,Mode=TwoWay}" SelectionMode="Single"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Grid ColumnDefinitions="2*,*" > <Button Text="My button" HeightRequest="40" HorizontalOptions="FillAndExpand" Margin="5,5" Focused="OnControlFocused" /> <Entry Text="{Binding NumValor,StringFormat='{0:c}'}" Keyboard="Numeric" Grid.Column="1" HorizontalTextAlignment="End" Margin="0,5,5,5" Focused="OnControlFocused"> </Entry> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
然后在页面的后台代码(.xaml.cs)中实现事件处理方法:
using Microsoft.Maui.Controls; namespace YourProjectNamespace; public partial class YourPage : ContentPage { public YourPage() { InitializeComponent(); } private void OnControlFocused(object sender, FocusEventArgs e) { var element = sender as VisualElement; // 查找当前控件所在的ViewCell var viewCell = FindParent<ViewCell>(element); if (viewCell != null && LstMedios != null) { // 设置SelectedItem为当前项的数据模型 LstMedios.SelectedItem = viewCell.BindingContext; } } // 通用父控件查找方法 private T FindParent<T>(VisualElement element) where T : VisualElement { var parent = element.Parent as VisualElement; while (parent != null) { if (parent is T typedParent) return typedParent; parent = parent.Parent as VisualElement; } return null; } }
原理说明
两种方法的核心逻辑是一致的:
- 当控件获得焦点时,递归查找它所在的
ViewCell - 获取
ViewCell的BindingContext(也就是当前ListView项对应的数据模型) - 将这个数据模型赋值给ListView的
SelectedItem属性,从而触发选中状态更新
内容的提问来源于stack exchange,提问作者Juan Pablo Gomez
相关产品推荐
相关产品推荐

