【问题标题】:Hiding expander when all content is collapsed折叠所有内容时隐藏扩展器
【发布时间】:2015-10-01 11:34:25
【问题描述】:

我有一个 WPF 数据网格,它有一个集合视图源,上面有 3 个级别的分组。

我已将数据网格设置为使用 3 个扩展器,使其看起来像这样:

Level 1 Expander
<content>
    Level 2 Expander
    <content>
        Level 3 Expander
        <content>

Level 2 和 Level 1 只是组的标题

我有第二个控件,它允许用户显示和隐藏 3 级项目,它通过将 3 级扩展器绑定到后面对象中的布尔“IsVisible”属性来工作。

       <!--  Style for groups under the top level. this is the style for how a sample is displayed  -->
        <GroupStyle>
            <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                    <Setter Property="Margin" Value="0,0,0,0" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type GroupItem}">

                                <!--  The parent control that determines whether or not an item needs to be displayed. This holds all of the sub controls displayed for a sample  -->
                                <Expander Margin="2"
                                          Background="{Binding Path=Name,
                                                               Converter={StaticResource SampleTypeToColourConverter}}"
                                          IsExpanded="True"
                                          Visibility="{Binding Path=Items[0].IsVisibleInMainScreen,
                                                               Converter={StaticResource BoolToVisibilityConverter}}">

这种方法效果非常好。

但是

如果用户取消选择 3 级扩展器中的所有项目,则 2 级扩展器标题仍会显示,这意味着有价值的房地产已用完,显示没有可见数据的组标题。

我想要一种将 2 级扩展器的可见性绑定到其子控件的方法,并说“如果所有子控件都可见,则显示扩展器,否则将其折叠”

这可能吗?

【问题讨论】:

  • 如果所有子项都可见,则显示扩展器,否则将其折叠听起来像是一个转换器任务。您已经拥有IsVisibleInMainWindow 属性,当孩子折叠时更改它。注意:Items 应该是ObservableCollection
  • 你能给我们一个更完整的xaml,包括所有的扩展器吗?
  • 我认为我们确实需要更多的 xaml。

标签: c# wpf xaml expander


【解决方案1】:

我找到了一种相当简单干净但并不完美的方法来实现您的目标。如果您没有太多组,这应该可以解决问题。

我刚刚将此触发器添加到GroupItem ControlTemplate

<ControlTemplate.Triggers>
    <DataTrigger Binding="{Binding ElementName=IP, Path=ActualHeight}" Value="0">
        <Setter Property="Visibility" Value="Hidden"/>
        <Setter Property="Height" Value="1"/>
    </DataTrigger>
</ControlTemplate.Triggers>

ItemsPresenter (IP) ActualSize 降至零时,它将几乎折叠标题。

为什么差不多?

当控件被初始化并且在绑定发生之前,ItemPresenter ActualHeight 为 0,当 Visibility 设置为 Collapsed 时,ItemPresenter 根本不会被渲染。

使用Visibility.Hidden 允许ItemsPresenter 进入渲染阶段并被测量。 我成功地将Height 降到 0.4 像素,但我怀疑这取决于设备。

【讨论】:

  • 我选择了这个答案,因为它在纯 xaml 中开箱即用几乎完美。这是我认为最简单的方法,尽管其他答案本身就有优点
【解决方案2】:

假设您使用的是 MVVM 类型的样式,您可以改为绑定到组对象的属性,如果所有子对象都不可见,则返回 false:

public bool AreChildrenVisible { get { return _children.Any(x=>x.IsVisibleInMainScreen); } }

或者,通过 Converter 类传递 Items 的集合,以根据组中所有 subItems 的聚合状态返回 Visibility。

【讨论】:

    【解决方案3】:

    这不是一个直接的答案,因为您必须根据您的需要专门实施它,但以前我使用网格控件的替代来创建成员的动态网格分配,如果没有可见的成员,则它会隐藏父组框。

    public class DynamicLayoutGrid : Grid
    {
    
           protected override void OnInitialized(EventArgs e)
           {
                    //Hook up the loaded event (this is used because it fires after the visibility binding has occurred)
                 this.Loaded += new RoutedEventHandler(DynamicLayoutGrid_Loaded);
    
                 base.OnInitialized(e);
            }
    
    
            void DynamicLayoutGrid_Loaded(object sender, RoutedEventArgs e)
            {
                int numberOfColumns = ColumnDefinitions.Count;
                int columnSpan = 0;
                int rowNum = 0;
                int columnNum = 0;
                int visibleCount = 0;
    
                foreach (UIElement child in Children)
                {
                    //We only want to layout visible items in the grid
                    if (child.Visibility != Visibility.Visible)
                    {
                        continue;
                    }
                    else
                    {
                        visibleCount++;
                    }
    
                    //Get the column span of the element if it is not in column 0 as we might need to take this into account
                    columnSpan = Grid.GetColumnSpan(child);
    
                    //set the Grid row of the element
                    Grid.SetRow(child, rowNum);
    
                    //set the grid column of the element (and shift it along if the previous element on this row had a rowspan greater than 0
                    Grid.SetColumn(child, columnNum);
    
                    //If there isn't any columnspan then just move to the next column normally
                    if (columnSpan == 0)
                    {
                        columnSpan = 1;
                    }
    
                    //Move to the next available column
                    columnNum += columnSpan;
    
                    //Move to the next row and start the columns again
                    if (columnNum >= numberOfColumns)
                    {
                        rowNum++;
                        columnNum = 0;
                    }
                }
    
                if (visibleCount == 0)
                {
                    if (this.Parent.GetType() == typeof(GroupBox))
                    {
                        (this.Parent as GroupBox).Visibility = Visibility.Collapsed;
                    }
                }
            }
        }
    

    【讨论】:

      【解决方案4】:

      使用 IMultiValueConverter 实现将项目转换为可见性。 如果所有项目 IsVisibleInMainScreen 属性返回 true,则转换器将返回可见,否则隐藏。

      在原始示例中用于转换第一项的同一位置使用转换器

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-10
        • 2014-06-03
        • 2016-09-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多