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

.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 &#10;.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="&#9660;" 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 15:29:56