.NET MAUI Picker SelectedIndex绑定初始不显示选中项问题
.NET MAUI Picker初始选中项不显示问题解决
问题描述
在.NET MAUI项目中使用Picker控件时,遇到初始加载无法展示绑定选中项的问题:点击Picker时,ItemSource、ItemDisplayBinding和SelectedItem均能正常工作,但视图首次显示时,Picker并未展示绑定列表中的对应选中对象。
项目代码
视图MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:models="clr-namespace:MauiPicker;assembly=MauiPicker" xmlns:viewModels="clr-namespace:MauiPicker" x:Class="MauiPicker.MainPage" x:DataType="viewModels:MainViewModel"> <Grid ColumnDefinitions="*" RowDefinitions="*,*"> <CollectionView Grid.Row="0" Grid.Column="0" ItemsSource="{Binding PartAResultLists}" SelectionMode="None"> <CollectionView.ItemTemplate> <DataTemplate x:DataType="models:PartAResultList"> <Grid Padding="5"> <Border> <Grid Padding="10" ColumnDefinitions="Auto,*" RowDefinitions="Auto" RowSpacing="7"> <Label Text="Outlet Type:" Grid.Column="0" Grid.Row="0" HorizontalOptions="End" VerticalOptions="Center" Margin="0,0,0,0"/> <Border Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2"> <Picker Title="Select an Outlet" ItemsSource="{Binding Source={RelativeSource AncestorType={x:Type viewModels:MainViewModel}}, Path=Outlets}" ItemDisplayBinding="{Binding Name}" SelectedIndex="{Binding OutletIndex}" SelectedItem="{Binding OutletName}"> </Picker> </Border> </Grid> </Border> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> <Button Grid.Row="1" Grid.Column="0" Text="Reload List" HorizontalOptions="Center" VerticalOptions="Center" Command="{Binding Source={RelativeSource AncestorType={x:Type viewModels:MainViewModel}}, Path=LoadResultsCommand}"> </Button> </Grid> </ContentPage>
代码后置文件MainPage.xaml.cs
namespace MauiPicker; public partial class MainPage : ContentPage { public MainPage(MainViewModel vm) { InitializeComponent(); BindingContext = vm; } }
视图模型MainViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using MvvmHelpers; namespace MauiPicker { public partial class MainViewModel : ObservableObject { public MainViewModel() { LoadResults(); } [RelayCommand] async Task LoadResults() { Outlets = new ObservableRangeCollection<Outlet> { new Outlet(){Name="Outlet0"}, new Outlet(){Name="Outlet1"}, new Outlet(){Name="Outlet2"}, }; PartAResultLists = new ObservableRangeCollection<PartAResultList> { new PartAResultList(){OutletIndex = 0, OutletName= new Outlet(){Name="Outlet0" } }, new PartAResultList(){OutletIndex=1, OutletName= new Outlet(){Name="Outlet1" }}, new PartAResultList(){OutletIndex = 2, OutletName= new Outlet(){Name="Outlet2" }}, new PartAResultList(){OutletIndex = 0, OutletName= new Outlet(){Name="Outlet0" }}, new PartAResultList(){OutletIndex = 2, OutletName= new Outlet(){Name="Outlet2" }} }; } [ObservableProperty] ObservableRangeCollection<Outlet> outlets; [ObservableProperty] ObservableRangeCollection<PartAResultList> partAResultLists; } }
模型类
Outlet.cs
using CommunityToolkit.Mvvm.ComponentModel; namespace MauiPicker { public partial class Outlet : ObservableObject { [ObservableProperty] public string name; } }
PartAResultList.cs
using CommunityToolkit.Mvvm.ComponentModel; namespace MauiPicker { public partial class PartAResultList : ObservableObject { [ObservableProperty] public Outlet outletName; [ObservableProperty] public int outletIndex; } }
MauiProgram.cs
using CommunityToolkit.Maui; using Microsoft.Extensions.Logging; namespace MauiPicker; public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .UseMauiCommunityToolkit() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); builder.Services.AddSingleton<MainPage>(); builder.Services.AddSingleton<MainViewModel>(); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } }
问题根源及解决方案
1. 对象实例不匹配
Picker的SelectedItem通过引用相等匹配ItemsSource中的对象。原代码中PartAResultList的OutletName是新建的Outlet实例,和Outlets集合中的实例并非同一对象,导致Picker无法识别选中项,初始加载时不显示。
2. 同时绑定SelectedIndex和SelectedItem
同时绑定两个属性可能引发冲突,Picker初始化时会优先处理其中一个,导致状态不一致。
修改方案
步骤1:复用Outlets集合中的实例
修改MainViewModel的LoadResults方法,让PartAResultList的OutletName直接引用Outlets中的对象:
[RelayCommand] async Task LoadResults() { Outlets = new ObservableRangeCollection<Outlet> { new Outlet(){Name="Outlet0"}, new Outlet(){Name="Outlet1"}, new Outlet(){Name="Outlet2"}, }; PartAResultLists = new ObservableRangeCollection<PartAResultList> { new PartAResultList(){OutletIndex = 0, OutletName= Outlets[0] }, new PartAResultList(){OutletIndex=1, OutletName= Outlets[1] }, new PartAResultList(){OutletIndex = 2, OutletName= Outlets[2] }, new PartAResultList(){OutletIndex = 0, OutletName= Outlets[0] }, new PartAResultList(){OutletIndex = 2, OutletName= Outlets[2] } }; }
步骤2:移除冗余绑定(可选)
建议只保留SelectedItem绑定避免冲突,修改Picker的XAML:
<Picker Title="Select an Outlet" ItemsSource="{Binding Source={RelativeSource AncestorType={x:Type viewModels:MainViewModel}}, Path=Outlets}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding OutletName}"> </Picker>
若需保留SelectedIndex绑定,需确保OutletIndex的值和OutletName在Outlets中的索引一致,但优先使用SelectedItem更直观可靠。
补充说明
若无法复用实例(如数据来自数据库),需重写Outlet类的Equals和GetHashCode方法,让Picker通过对象内容而非引用判断相等性:
public partial class Outlet : ObservableObject { [ObservableProperty] public string name; public override bool Equals(object obj) { return obj is Outlet outlet && name == outlet.name; } public override int GetHashCode() { return HashCode.Combine(name); } }
内容的提问来源于stack exchange,提问作者scott
相关产品推荐
相关产品推荐

