.NET MAUI模拟ComboBox:绑定失效与列表无法关闭问题排查
.NET MAUI Expander模拟ComboBox的问题修复
问题描述
学习.NET MAUI时,用Expander模拟ComboBox功能,适配.NET 8(VS 17.10.4 + Windows 11)后遇到两个问题:
- 点击列表项后,头部Label的选中文本不更新
- 选中项后,展开的列表无法自动关闭
初始代码
MauiProgram.cs
using CommunityToolkit.Maui; using Microsoft.Extensions.Logging; namespace Combox { 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"); }); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } } }
MainViewModel.cs
using System.Collections.ObjectModel; using System.Diagnostics; using System.Windows.Input; namespace Combox.ViewModels { public partial class MainViewModel : BindableObject { string _selectedText = "Select the item"; public string SelectedText { get { return _selectedText; } private set { _selectedText = value; } } bool _isOpened; public bool IsOpened { get { return _isOpened; } private set { _isOpened = value; } } ObservableCollection<string>? _dataList; public ObservableCollection<string>? DataList { get { return _dataList; } private set { _dataList = value; } } public ICommand SelectionCommand { private set; get; } public MainViewModel() { DataList = new ObservableCollection<string>()!; DataList.Add("Item1"); DataList.Add("Item2"); DataList.Add("Item3"); DataList.Add("Item4"); DataList.Add("Item5"); SelectionCommand = new Command( execute: () => { IsOpened = false; Debug.Write($"SelectedText {SelectedText}"); RefreshCanExecute(); }, canExecute: () => { return !IsOpened; }); } void RefreshCanExecute() { ((Command)SelectionCommand).ChangeCanExecute(); } } }
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:local="clr-namespace:Combox.ViewModels" x:Class="Combox.MainPage" x:Name="mainView"> <ContentPage.BindingContext> <local:MainViewModel /> </ContentPage.BindingContext> <ScrollView> <VerticalStackLayout Padding="30,0" Spacing="25"> <Image Source="dotnet_bot.png" HeightRequest="185" Aspect="AspectFit" SemanticProperties.Description="dot net bot in a race car number eight" /> <Label Text="Hello, World!" Style="{StaticResource Headline}" SemanticProperties.HeadingLevel="Level1" /> <Label Text="Welcome to .NET Multi-platform App UI" Style="{StaticResource SubHeadline}" SemanticProperties.HeadingLevel="Level2" SemanticProperties.Description="Welcome to dot net Multi platform App U I" /> <toolkit:Expander IsExpanded="{Binding IsOpened}" HeightRequest="190"> <toolkit:Expander.Header> <HorizontalStackLayout MaximumHeightRequest="42" Padding="10"> <Label HorizontalOptions="Start" Text="{Binding SelectedText}" /> <Label Text="▼" HorizontalOptions="EndAndExpand" VerticalOptions="Center" /> </HorizontalStackLayout> </toolkit:Expander.Header> <CollectionView ItemsSource="{Binding DataList}" HeightRequest="190" SelectionMode="Single" SelectedItem="{Binding SelectedText}" SelectionChangedCommand="{Binding SelectionCommand}"> <CollectionView.ItemTemplate> <DataTemplate> <Label Text="{Binding}"> </Label> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </toolkit:Expander> <Button x:Name="CounterBtn" Text="Click me" SemanticProperties.Hint="Counts the number of times you click" Clicked="OnCounterClicked" HorizontalOptions="Fill" /> </VerticalStackLayout> </ScrollView> </ContentPage>
修复后的MainViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel; using System.Collections.ObjectModel; using System.Windows.Input; namespace Combox.ViewModels { public partial class MainViewModel : ObservableObject { string _selectedText = "Select the item"; public string SelectedText { get { return _selectedText; } set { SetProperty(ref _selectedText, value); } } bool _isOpened = false; public bool IsOpened { get { return _isOpened; } private set { SetProperty(ref _isOpened, value); } } ObservableCollection<string>? _dataList; public ObservableCollection<string>? DataList { get { return _dataList; } private set { _dataList = value; } } public ICommand SelectionCommand { private set; get; } public MainViewModel() { DataList = new ObservableCollection<string>()!; DataList.Add("Item1"); DataList.Add("Item2"); DataList.Add("Item3"); DataList.Add("Item4"); DataList.Add("Item5"); SelectionCommand = new Command( execute: () => { IsOpened = false; RefreshCanExecutes(); }, canExecute: () => { IsOpened = true; return true; }); } void RefreshCanExecutes() { ((Command)SelectionCommand).ChangeCanExecute(); } } }
问题解决要点
- 绑定更新修复:将ViewModel继承的
BindableObject替换为MVVM Community Toolkit的ObservableObject,使用SetProperty实现属性变更通知,确保SelectedText和IsOpened的变化能同步到UI。 - 列表折叠修复:调整
SelectionCommand的canExecute逻辑,移除原有的!IsOpened判断,改为执行时设置IsOpened = true并返回true,确保选中项后能正常触发execute方法将IsOpened设为false,关闭Expander。
内容的提问来源于stack exchange,提问作者user3017691
相关产品推荐
相关产品推荐

