如何访问 WPF GroupItem 的模板中的元素
How to access an element in the Template of a WPF GroupItem
我有一个 ListView
,里面装满了一些物品。这些项目有两个属性,ItemName
和 ItemGroup
,我想按第二个 属性 对它们进行分组。所以我写了这样的东西:
<Grid>
<Grid.Resources>
<Style x:Key="groupStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False" Header="{Binding Name}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListView x:Name="lv">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupStyle}"/>
</ListView.GroupStyle>
</ListView>
</Grid>
在后面的代码中
// here, list is the collection of items with mentioned properties.
lv.ItemsSource = list;
var view = (CollectionView) CollectionViewSource.GetDefaultView(lv.ItemsSource);
if (view.GroupDescriptions != null)
{
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("ItemGroup"));
}
现在一切顺利。但问题是,有时我想展开代码隐藏中的所有 Expander
,但我找不到访问它们并将它们的 IsExpanded
属性 设置为 true 的方法。我该怎么做?
编辑:这是我用来查找扩展器的方法,例如FindChildren<Expander>(lv)
但它总是 return 一个空集合
public static IEnumerable<T> FindChildren<T>(DependencyObject obj) where T : DependencyObject
{
if (obj == null)
{
yield break;
}
int vt_count = obj is Visual ? VisualTreeHelper.GetChildrenCount(obj) : 0;
var children = vt_count > 0
? Enumerable.Range(0, vt_count).Select(n => VisualTreeHelper.GetChild(obj, n))
: LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>();
foreach (var child in children)
{
if (child is T)
{
yield return (T) child;
continue;
}
foreach (T descendant in FindChildren<T>(child))
yield return descendant;
}
}
您可以使用递归方法在可视化树中找到 Expander
元素,并且 VisualTreeHelper
class:
private void ExpandButton_Click(object sender, RoutedEventArgs e)
{
foreach (Expander gi in FindVisualChildren<Expander>(lv))
{
gi.IsExpanded = true;
}
}
private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
编辑: 如果您想在设置 ListView
的 ItemsSource
属性 后立即执行此操作,您需要等到容器创建完毕。处理 Loaded
事件:
public MainWindow()
{
InitializeComponent();
// here, list is the collection of items with mentioned properties.
lv.ItemsSource = list;
var view = (CollectionView)CollectionViewSource.GetDefaultView(lv.ItemsSource);
if (view.GroupDescriptions != null)
{
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("ItemGroup"));
}
Loaded += (s, e) =>
{
foreach (Expander gi in FindVisualChildren<Expander>(lv))
{
gi.IsExpanded = true;
}
};
}
很奇怪,@mm8 发布的答案没有用,我不知道为什么。但无论如何我设法做了一个解决方法。关键是将扩展器的 IsExpanded
属性 绑定到 ListView
的未使用的 属性,例如它的标签:
<ControlTemplate>
<Expander Header="{Binding Name}">
<Expander.IsExpanded>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ListView}" Path="Tag" />
</Expander.IsExpanded>
<ItemsPresenter />
</Expander>
</ControlTemplate>
然后你可以通过在代码中设置lv.Tag = true;
或lv.Tag = false;
来控制所有的IsExpanded
属性。
我有一个 ListView
,里面装满了一些物品。这些项目有两个属性,ItemName
和 ItemGroup
,我想按第二个 属性 对它们进行分组。所以我写了这样的东西:
<Grid>
<Grid.Resources>
<Style x:Key="groupStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False" Header="{Binding Name}">
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListView x:Name="lv">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupStyle}"/>
</ListView.GroupStyle>
</ListView>
</Grid>
在后面的代码中
// here, list is the collection of items with mentioned properties.
lv.ItemsSource = list;
var view = (CollectionView) CollectionViewSource.GetDefaultView(lv.ItemsSource);
if (view.GroupDescriptions != null)
{
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("ItemGroup"));
}
现在一切顺利。但问题是,有时我想展开代码隐藏中的所有 Expander
,但我找不到访问它们并将它们的 IsExpanded
属性 设置为 true 的方法。我该怎么做?
编辑:这是我用来查找扩展器的方法,例如FindChildren<Expander>(lv)
但它总是 return 一个空集合
public static IEnumerable<T> FindChildren<T>(DependencyObject obj) where T : DependencyObject
{
if (obj == null)
{
yield break;
}
int vt_count = obj is Visual ? VisualTreeHelper.GetChildrenCount(obj) : 0;
var children = vt_count > 0
? Enumerable.Range(0, vt_count).Select(n => VisualTreeHelper.GetChild(obj, n))
: LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>();
foreach (var child in children)
{
if (child is T)
{
yield return (T) child;
continue;
}
foreach (T descendant in FindChildren<T>(child))
yield return descendant;
}
}
您可以使用递归方法在可视化树中找到 Expander
元素,并且 VisualTreeHelper
class:
private void ExpandButton_Click(object sender, RoutedEventArgs e)
{
foreach (Expander gi in FindVisualChildren<Expander>(lv))
{
gi.IsExpanded = true;
}
}
private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
编辑: 如果您想在设置 ListView
的 ItemsSource
属性 后立即执行此操作,您需要等到容器创建完毕。处理 Loaded
事件:
public MainWindow()
{
InitializeComponent();
// here, list is the collection of items with mentioned properties.
lv.ItemsSource = list;
var view = (CollectionView)CollectionViewSource.GetDefaultView(lv.ItemsSource);
if (view.GroupDescriptions != null)
{
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("ItemGroup"));
}
Loaded += (s, e) =>
{
foreach (Expander gi in FindVisualChildren<Expander>(lv))
{
gi.IsExpanded = true;
}
};
}
很奇怪,@mm8 发布的答案没有用,我不知道为什么。但无论如何我设法做了一个解决方法。关键是将扩展器的 IsExpanded
属性 绑定到 ListView
的未使用的 属性,例如它的标签:
<ControlTemplate>
<Expander Header="{Binding Name}">
<Expander.IsExpanded>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ListView}" Path="Tag" />
</Expander.IsExpanded>
<ItemsPresenter />
</Expander>
</ControlTemplate>
然后你可以通过在代码中设置lv.Tag = true;
或lv.Tag = false;
来控制所有的IsExpanded
属性。