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

优化.NET MAUI BottomSheet中ListView的图片切换逻辑

优化实现方案

核心思路是用单一布尔属性控制展开/收起状态,简化控件结构与后台逻辑,避免冗余的布尔属性和控件依赖:


1. 重构数据模型

将两个布尔属性合并为单个IsExpanded属性,状态更清晰,仅需维护这一个字段:

public class MenuModel : INotifyPropertyChanged
{
    private bool _isExpanded;
    public string MenuTitle { get; set; }

    public bool IsExpanded
    {
        get => _isExpanded;
        set
        {
            _isExpanded = value;
            OnPropertyChanged();
        }
    }

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

2. 简化命令逻辑

点击时仅需切换IsExpanded的值,无需处理多属性联动:

public ICommand GestureCommand => new Command<MenuModel>(menu =>
{
    menu.IsExpanded = !menu.IsExpanded;
});

3. 优化XAML结构

去掉冗余的Image控件,通过DataTrigger或转换器实现图片切换,Label的边距直接绑定状态属性:

方式一:用DataTrigger实现(无需写转换器)

<ContentPage.Resources>
    <!-- 可省略转换器,直接用触发器切换图片 -->
</ContentPage.Resources>

<ListView ItemsSource="{Binding Menus}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid>
                    <Grid.GestureRecognizers>
                        <TapGestureRecognizer 
                            Command="{Binding Source={RelativeSource AncestorType={x:Type local:YourViewModel}}, Path=GestureCommand}" 
                            CommandParameter="{Binding .}" />
                    </Grid.GestureRecognizers>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <!-- 单个Image,通过触发器切换箭头方向 -->
                    <Image Grid.Column="0" Margin="10">
                        <Image.Triggers>
                            <DataTrigger TargetType="Image" Binding="{Binding IsExpanded}" Value="False">
                                <Setter Property="Source" Value="arrow_downward.png" />
                            </DataTrigger>
                            <DataTrigger TargetType="Image" Binding="{Binding IsExpanded}" Value="True">
                                <Setter Property="Source" Value="arrow_upward.png" />
                            </DataTrigger>
                        </Image.Triggers>
                    </Image>

                    <!-- Label边距绑定状态 -->
                    <mdc:Label 
                        Grid.Column="1" 
                        Text="{Binding MenuTitle}" 
                        HorizontalOptions="Start" 
                        HeightRequest="30"
                        Margin="10,0,0,0">
                        <mdc:Label.Triggers>
                            <DataTrigger TargetType="mdc:Label" Binding="{Binding IsExpanded}" Value="True">
                                <Setter Property="Margin" Value="44,0,0,0" />
                            </DataTrigger>
                        </mdc:Label.Triggers>
                    </mdc:Label>
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

方式二:用转换器实现(适合复用场景)

先创建布尔转图片源的转换器:

public class BoolToArrowImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is bool isExpanded 
            ? isExpanded ? "arrow_upward.png" : "arrow_downward.png" 
            : "arrow_downward.png";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后在XAML中引用并使用:

<ContentPage.Resources>
    <local:BoolToArrowImageConverter x:Key="BoolToArrowImage" />
</ContentPage.Resources>

<ListView ItemsSource="{Binding Menus}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid>
                    <Grid.GestureRecognizers>
                        <TapGestureRecognizer 
                            Command="{Binding Source={RelativeSource AncestorType={x:Type local:YourViewModel}}, Path=GestureCommand}" 
                            CommandParameter="{Binding .}" />
                    </Grid.GestureRecognizers>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <!-- 单个Image,绑定转换器切换图片 -->
                    <Image Grid.Column="0" 
                           Source="{Binding IsExpanded, Converter={StaticResource BoolToArrowImage}}" 
                           Margin="10" />

                    <!-- Label边距绑定状态 -->
                    <mdc:Label 
                        Grid.Column="1" 
                        Text="{Binding MenuTitle}" 
                        HorizontalOptions="Start" 
                        HeightRequest="30"
                        Margin="10,0,0,0">
                        <mdc:Label.Triggers>
                            <DataTrigger TargetType="mdc:Label" Binding="{Binding IsExpanded}" Value="True">
                                <Setter Property="Margin" Value="44,0,0,0" />
                            </DataTrigger>
                        </mdc:Label.Triggers>
                    </mdc:Label>
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

优化亮点

  • 去掉冗余控件与属性:从两个Image和两个布尔属性,简化为单个Image和单个IsExpanded属性
  • 降低耦合:Label的样式直接绑定模型状态,不再依赖其他控件的可见性
  • 逻辑清晰:后台仅需维护一个状态字段,命令处理极简

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 09:34:55