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

XAML Forms中如何根据首个Picker选择筛选第二个Picker数据?

解决方案:基于MVVM的双Picker联动过滤实现

核心思路是将所有逻辑移至ViewModel层,通过属性绑定替代View层事件处理,既解决集合访问问题,又实现联动过滤与状态控制,全程无需第三方控件。


1. ViewModel实现(核心逻辑)

ViewModel需保存原始数据集合,通过选中属性触发过滤,并实现属性变更通知以同步UI:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

public class TerritoryTrackViewModel : INotifyPropertyChanged
{
    // 私有存储原始数据,避免直接绑定到UI导致过滤丢失源数据
    private ObservableCollection<Territory> _allTerritories;
    private ObservableCollection<Track> _allTracks;

    // 绑定到第一个Picker的区域集合
    public ObservableCollection<Territory> Territories => _allTerritories;

    // 绑定到第二个Picker的过滤后轨道集合
    private ObservableCollection<Track> _filteredTracks;
    public ObservableCollection<Track> FilteredTracks
    {
        get => _filteredTracks;
        set
        {
            _filteredTracks = value;
            OnPropertyChanged();
        }
    }

    // 选中的区域,绑定到第一个Picker的SelectedItem
    private Territory _selectedTerritory;
    public Territory SelectedTerritory
    {
        get => _selectedTerritory;
        set
        {
            _selectedTerritory = value;
            OnPropertyChanged();
            // 选中区域后自动触发轨道过滤
            FilterTracksForSelectedTerritory();
            // 通知启用状态变更
            OnPropertyChanged(nameof(IsTrackPickerEnabled));
        }
    }

    // 第二个Picker的启用状态:未选中区域时禁用
    public bool IsTrackPickerEnabled => SelectedTerritory != null;

    public TerritoryTrackViewModel()
    {
        _allTerritories = new ObservableCollection<Territory>();
        _allTracks = new ObservableCollection<Track>();
        _filteredTracks = new ObservableCollection<Track>();
        
        // 初始化加载数据
        LoadDataAsync();
    }

    private async void LoadDataAsync()
    {
        // 替换为你的实际API调用逻辑
        var territories = await YourApiClient.GetTerritoriesAsync();
        var tracks = await YourApiClient.GetTracksAsync();

        // 填充原始集合
        _allTerritories.Clear();
        foreach (var territory in territories) _allTerritories.Add(territory);
        
        _allTracks.Clear();
        foreach (var track in tracks) _allTracks.Add(track);
    }

    private void FilterTracksForSelectedTerritory()
    {
        FilteredTracks.Clear();
        if (SelectedTerritory == null) return;

        // 根据区域ID过滤轨道(需根据你的实体类属性调整匹配逻辑)
        var matchedTracks = _allTracks.Where(t => t.TerritoryId == SelectedTerritory.Id);
        foreach (var track in matchedTracks) FilteredTracks.Add(track);
    }

    // INotifyPropertyChanged 实现,确保属性变更同步到UI
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

// 示例实体类(需根据你的实际结构调整)
public class Territory
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Track
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int TerritoryId { get; set; }
}

2. XAML布局实现

通过数据绑定将Picker与ViewModel属性关联,无需编写后台事件代码:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourAppNamespace"
             x:Class="YourAppNamespace.MainPage">
    <ContentPage.BindingContext>
        <local:TerritoryTrackViewModel />
    </ContentPage.BindingContext>
    
    <StackLayout Padding="20" Spacing="15">
        <!-- 区域选择Picker -->
        <Picker Title="选择区域"
                ItemsSource="{Binding Territories}"
                SelectedItem="{Binding SelectedTerritory}"
                ItemDisplayBinding="{Binding Name}" />

        <!-- 轨道选择Picker:未选区域时禁用,显示过滤后的结果 -->
        <Picker Title="选择轨道"
                ItemsSource="{Binding FilteredTracks}"
                IsEnabled="{Binding IsTrackPickerEnabled}"
                ItemDisplayBinding="{Binding Name}" />
    </StackLayout>
</ContentPage>

关键要点说明

  1. 原始数据保留:用私有字段存储_allTerritories和_allTracks,避免过滤时丢失源数据,解决API加载后集合为空的问题。
  2. 联动触发逻辑:通过SelectedTerritory的setter自动触发过滤,替代View层的SelectedIndexChanged事件,确保ViewModel能直接访问所有数据。
  3. 状态控制:通过IsTrackPickerEnabled属性直接绑定到第二个Picker的IsEnabled,无需额外转换器即可实现未选中时禁用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 10:27:12