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

如何在.NET MAUI中为Picker组件实现搜索功能

.NET MAUI Android Picker 搜索功能实现方案

一、现成带搜索的Picker组件

.NET MAUI官方Picker本身没有集成搜索功能,但社区和第三方控件库提供了现成的解决方案:

  • CommunityToolkit.Maui:可通过Popup结合内置控件快速实现带搜索的选择器,也支持扩展的选择器组件;
  • Syncfusion MAUI Controls:SfPicker组件原生支持搜索筛选功能;
  • Telerik UI for MAUI:RadPicker组件内置了搜索过滤能力。

如果不想引入第三方库,可以手动实现,以下是具体步骤。

二、手动实现带搜索的Picker

核心思路是用Popup组件替代原生Picker的弹出层,在Popup内放置SearchBar和ListView,通过搜索文本实时过滤列表数据。

1. ViewModel 逻辑实现

在ViewModel中定义数据源、过滤后的集合、搜索文本属性及过滤逻辑:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace YourAppNamespace;

public class MainViewModel : INotifyPropertyChanged
{
    // 原始完整数据源
    private List<string> _originalItems = new List<string>();
    // 过滤后的显示数据源
    private ObservableCollection<string> _filteredItems = new ObservableCollection<string>();
    private string _searchText = string.Empty;

    public ObservableCollection<string> FilteredItems
    {
        get => _filteredItems;
        set
        {
            _filteredItems = value;
            OnPropertyChanged();
        }
    }

    public string SearchText
    {
        get => _searchText;
        set
        {
            _searchText = value;
            OnPropertyChanged();
            FilterItems();
        }
    }

    // 选中项命令
    public ICommand SelectItemCommand { get; }
    // 关闭Popup命令
    public ICommand ClosePopupCommand { get; }

    public MainViewModel()
    {
        // 初始化100+条测试数据
        for (int i = 1; i <= 150; i++)
        {
            _originalItems.Add($"选项 {i}");
        }
        FilteredItems = new ObservableCollection<string>(_originalItems);
        SelectItemCommand = new Command<string>(OnItemSelected);
        ClosePopupCommand = new Command(() => OnClosePopup?.Invoke());
    }

    // 过滤逻辑
    private void FilterItems()
    {
        if (string.IsNullOrWhiteSpace(SearchText))
        {
            FilteredItems.Clear();
            foreach (var item in _originalItems)
            {
                FilteredItems.Add(item);
            }
            return;
        }

        var filtered = _originalItems.Where(item => 
            item.IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
        FilteredItems.Clear();
        foreach (var item in filtered)
        {
            FilteredItems.Add(item);
        }
    }

    private void OnItemSelected(string selectedItem)
    {
        // 处理选中逻辑,比如赋值给页面的绑定属性
        SelectedItem = selectedItem;
        OnClosePopup?.Invoke();
    }

    private string _selectedItem;
    public string SelectedItem
    {
        get => _selectedItem;
        set
        {
            _selectedItem = value;
            OnPropertyChanged();
        }
    }

    // Popup关闭回调
    public Action OnClosePopup { get; set; }

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

2. XAML 页面实现

在页面中添加触发按钮(替代原生Picker的点击区域),并定义Popup内容:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:YourAppNamespace"
             x:Class="YourAppNamespace.MainPage">
    <ContentPage.BindingContext>
        <vm:MainViewModel />
    </ContentPage.BindingContext>

    <StackLayout Padding="20" VerticalOptions="Center">
        <!-- 模拟Picker的显示区域 -->
        <Frame BorderColor="Gray" CornerRadius="5" Padding="10" Tapped="Frame_Tapped">
            <Label Text="{Binding SelectedItem, FallbackValue='请选择选项'}" />
        </Frame>

        <!-- 带搜索的选择Popup -->
        <Popup x:Name="SearchPickerPopup"
               Size="300, 400"
               IsLightDismissEnabled="True">
            <VerticalStackLayout>
                <SearchBar Placeholder="搜索选项"
                           Text="{Binding SearchText}"
                           Margin="10" />
                <ListView x:Name="listView"
                          ItemsSource="{Binding FilteredItems}"
                          Margin="10"
                          SelectionMode="Single">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextCell Text="{Binding .}" />
                        </DataTemplate>
                    </ListView.ItemTemplate>
                    <ListView.Behaviors>
                        <EventToCommandBehavior EventName="ItemSelected"
                                                Command="{Binding SelectItemCommand}"
                                                CommandParameter="{Binding SelectedItem, Source={x:Reference listView}}" />
                    </ListView.Behaviors>
                </ListView>
                <Button Text="取消"
                        Command="{Binding ClosePopupCommand}"
                        Margin="10" />
            </VerticalStackLayout>
        </Popup>
    </StackLayout>
</ContentPage>

3. 页面后台代码

处理触发Popup的逻辑:

namespace YourAppNamespace;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        if (BindingContext is MainViewModel vm)
        {
            vm.OnClosePopup = () => SearchPickerPopup.IsOpen = false;
        }
    }

    private void Frame_Tapped(object sender, TappedEventArgs e)
    {
        SearchPickerPopup.IsOpen = true;
    }
}

4. 排查之前TextChanged事件失败的可能原因

你之前用SearchBar的TextChanged没成功,大概率是以下问题:

  • 原生Picker的ItemsSource绑定后,弹出层无法实时刷新数据源(这是原生Picker的局限,因此推荐用Popup替代);
  • 过滤逻辑未正确处理空文本或大小写匹配场景;
  • 未实现INotifyPropertyChanged接口,导致UI无法接收数据源更新通知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 17:07:40