折叠所有内容时隐藏扩展器
Hiding expander when all content is collapsed
我有一个 WPF 数据网格,它有一个 Collection View Source,上面有 3 个级别的分组。
我已将数据网格设置为使用 3 个扩展器,如下所示:
Level 1 Expander
<content>
Level 2 Expander
<content>
Level 3 Expander
<content>
Level 2 和 Level 1 只是组的标题
我有第二个控件,允许用户显示和隐藏 3 级项目,它通过将 3 级扩展器绑定到 object 后面的布尔值 "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 级扩展器 header 仍会显示,这意味着宝贵的空间已用完,显示 header 没有可见数据的组.
我想要的是一种将 2 级扩展器的可见性绑定到其 child 控件并说 "If all children are visible then show the expander, otherwise collapse it"
的方法
这可能吗?
这不是一个直接的答案,因为您必须根据自己的需要专门实施它,但之前我使用了网格控件的覆盖来创建成员的动态网格分配,如果没有可见成员的话然后隐藏父组框。
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;
}
}
}
}
假设您使用的是 MVVM 类型的样式,则可以改为绑定到组对象的 属性,如果所有子对象都不可见,则 returns false:
public bool AreChildrenVisible { get { return _children.Any(x=>x.IsVisibleInMainScreen); } }
或者,通过转换器 class 将项目集合传递到 return 可见性,具体取决于组中所有子项目的聚合状态。
使用 IMultiValueConverter 实现将项目转换为可见性。
如果所有项目 IsVisibleInMainScreen 属性 return true 转换器将 return 可见,否则隐藏。
在 U 用于转换原始示例中的第一项的相同位置使用转换器
我找到了一种相当简单明了但并不完美的方法来实现您的目标。如果你没有太多的组,这应该可以解决问题。
我刚刚将此触发器添加到 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
降为零时,它会 几乎 崩溃 header。
为什么差不多?
当控件初始化且绑定发生之前,ItemPresenter ActualHeight
为 0,当 Visibility
设置为 Collapsed
时,ItemPresenter
未获取完全呈现。
使用 Visibility.Hidden
允许 ItemsPresenter
进入渲染阶段并进行测量。
我成功地将 Height
降低到 .4 px,但我怀疑这与设备有关。
我有一个 WPF 数据网格,它有一个 Collection View Source,上面有 3 个级别的分组。
我已将数据网格设置为使用 3 个扩展器,如下所示:
Level 1 Expander
<content>
Level 2 Expander
<content>
Level 3 Expander
<content>
Level 2 和 Level 1 只是组的标题
我有第二个控件,允许用户显示和隐藏 3 级项目,它通过将 3 级扩展器绑定到 object 后面的布尔值 "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 级扩展器 header 仍会显示,这意味着宝贵的空间已用完,显示 header 没有可见数据的组.
我想要的是一种将 2 级扩展器的可见性绑定到其 child 控件并说 "If all children are visible then show the expander, otherwise collapse it"
的方法这可能吗?
这不是一个直接的答案,因为您必须根据自己的需要专门实施它,但之前我使用了网格控件的覆盖来创建成员的动态网格分配,如果没有可见成员的话然后隐藏父组框。
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;
}
}
}
}
假设您使用的是 MVVM 类型的样式,则可以改为绑定到组对象的 属性,如果所有子对象都不可见,则 returns false:
public bool AreChildrenVisible { get { return _children.Any(x=>x.IsVisibleInMainScreen); } }
或者,通过转换器 class 将项目集合传递到 return 可见性,具体取决于组中所有子项目的聚合状态。
使用 IMultiValueConverter 实现将项目转换为可见性。 如果所有项目 IsVisibleInMainScreen 属性 return true 转换器将 return 可见,否则隐藏。
在 U 用于转换原始示例中的第一项的相同位置使用转换器
我找到了一种相当简单明了但并不完美的方法来实现您的目标。如果你没有太多的组,这应该可以解决问题。
我刚刚将此触发器添加到 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
降为零时,它会 几乎 崩溃 header。
为什么差不多?
当控件初始化且绑定发生之前,ItemPresenter ActualHeight
为 0,当 Visibility
设置为 Collapsed
时,ItemPresenter
未获取完全呈现。
使用 Visibility.Hidden
允许 ItemsPresenter
进入渲染阶段并进行测量。
我成功地将 Height
降低到 .4 px,但我怀疑这与设备有关。