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

.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;
    }
}

原理说明

两种方法的核心逻辑是一致的:

  1. 当控件获得焦点时,递归查找它所在的ViewCell
  2. 获取ViewCell的BindingContext(也就是当前ListView项对应的数据模型)
  3. 将这个数据模型赋值给ListView的SelectedItem属性,从而触发选中状态更新

内容的提问来源于stack exchange,提问作者Juan Pablo Gomez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 10:35:42