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

如何基于Expander的IsExpanded状态切换GridView相邻列StackPanel可见性?

解决方案:根据Expander展开状态切换相邻列StackPanel可见性

要实现这个需求,有两种常用方案,优先推荐MVVM模式的实现方式,耦合度更低;如果不想修改ViewModel,也可以通过后台代码结合视觉树查找来处理。

方案一:MVVM模式(推荐)

核心思路是给数据模型Record添加一个IsExpanded属性,绑定到第一列的Expander上,然后其他列的StackPanel通过这个属性控制可见性。

步骤1:修改Record模型

添加IsExpanded属性并实现INotifyPropertyChanged接口:

public class Record : INotifyPropertyChanged
{
    // 原有属性...
    public string Name { get; set; }
    public List<Limit> Limits { get; set; }

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

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

public class Limit
{
    public string Name { get; set; }
    public string HiLimit { get; set; }
}

步骤2:修改XAML代码

  • 绑定Expander的IsExpanded到Record.IsExpanded
  • 给相邻列的StackPanel添加Visibility绑定,用BooleanToVisibilityConverter转换状态

首先在Window/UserControl的资源里添加转换器:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>
</Window.Resources>

然后修改GridView列的模板:

<ListView ItemsSource="{Binding Records}">
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Records" Width="120">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate DataType="{x:Type local:Record}">
                            <!-- 绑定IsExpanded到模型属性 -->
                            <Expander Header="{Binding Name}" IsExpanded="{Binding IsExpanded, Mode=TwoWay}">
                                <ItemsControl ItemsSource="{Binding Limits}">
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel Orientation="Horizontal">
                                                <Border Width="25"/>
                                                <CheckBox/>
                                                <Border Width="5"/>
                                                <TextBlock Text="{Binding Name}"/>
                                            </StackPanel>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </Expander>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

                <GridViewColumn Header="HiLimit" Width="80">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate DataType="{x:Type local:Record}">
                            <!-- 通过转换器绑定可见性到IsExpanded -->
                            <StackPanel Width="70" Visibility="{Binding IsExpanded, Converter={StaticResource BoolToVisConverter}}">
                                <Border Height="21"/>
                                <ItemsControl ItemsSource="{Binding Limits}">
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <TextBox Text="{Binding HiLimit}"/>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </StackPanel>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

方案二:后台代码+视觉树查找

如果不想修改ViewModel,可以通过Expander的Expanded和Collapsed事件,查找当前行对应的其他列StackPanel,手动切换可见性。

步骤1:给Expander添加事件

<Expander Header="{Binding Name}" Expanded="Expander_Expanded" Collapsed="Expander_Collapsed">
    <!-- 原有内容 -->
</Expander>

步骤2:实现后台事件处理

private void Expander_Expanded(object sender, RoutedEventArgs e)
{
    ToggleStackPanelVisibility(sender, Visibility.Visible);
}

private void Expander_Collapsed(object sender, RoutedEventArgs e)
{
    ToggleStackPanelVisibility(sender, Visibility.Collapsed);
}

private void ToggleStackPanelVisibility(object sender, Visibility targetVisibility)
{
    var expander = sender as Expander;
    if (expander == null) return;

    // 查找当前所在的GridViewRow
    var gridViewRow = FindVisualParent<GridViewRow>(expander);
    if (gridViewRow == null) return;

    // 获取HiLimit列的单元格内容(StackPanel)
    var hiLimitCell = gridViewRow.Cells[1]; // 假设HiLimit是第二列,索引为1
    var stackPanel = hiLimitCell.ContentTemplate.LoadContent() as StackPanel;
    if (stackPanel != null)
    {
        stackPanel.Visibility = targetVisibility;
    }
}

// 通用视觉树查找父元素方法
private T FindVisualParent<T>(DependencyObject child) where T : DependencyObject
{
    var parentObject = VisualTreeHelper.GetParent(child);
    if (parentObject == null) return null;

    if (parentObject is T parent)
        return parent;
    else
        return FindVisualParent<T>(parentObject);
}

为什么ControlTemplate触发器无法直接实现?

因为每个GridViewColumn的CellTemplate都是独立的DataTemplate,不同列的元素属于不同的模板作用域,ControlTemplate触发器只能访问当前模板内的元素,无法跨模板引用其他列的控件,所以这种场景下触发器方案不适用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:24:53