【问题标题】:How to access an element in the Template of a WPF GroupItem如何访问 WPF GroupItem 模板中的元素
【发布时间】:2023-03-27 14:29:01
【问题描述】:

我有一个ListView,里面装满了一些物品。这些项目有两个属性,ItemNameItemGroup,我想按它们的第二个属性对它们进行分组。所以我写了这样的东西:

<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"));
}

现在一切顺利。但问题是,有时我想在后面的代码中展开所有Expanders,我发现无法访问它们并将它们的IsExpanded 属性设置为true。我该怎么做?

编辑:这是我用来查找扩展器的方法,例如FindChildren&lt;Expander&gt;(lv) 但它总是返回一个空集合

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;
    }
}

【问题讨论】:

    标签: c# wpf controltemplate expander


    【解决方案1】:

    您可以使用递归方法和VisualTreeHelper 类在可视化树中找到Expander 元素:

    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;
                }
            }
        }
    }
    

    编辑:如果您想在设置ListViewItemsSource 属性后立即执行此操作,则需要等到容器创建完成。处理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;
            }
        };
    }
    

    【讨论】:

    • 这段代码运行良好。 @polfosol 您是从事件侦听器调用代码还是将其附加到 view.GroupDescriptions.Add(new PropertyGroupDescription("ItemGroup")); 之后?
    • 标记是我的代码的一个简短的最小版本。但我很确定它不起作用。我的项目基于.net 4客户端,我使用的是win 7和vs2013
    • 谁说你应该从构造函数中调用它?到那时,还没有创建容器。我的示例使用事件处理程序。
    • 查看我的编辑,了解如何在实际创建容器后扩展扩展器。
    • 只是第二点:@mm8 提供的所有示例代码都适用于我的示例解决方案。
    【解决方案2】:

    奇怪,@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属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-07
      • 1970-01-01
      • 2017-03-09
      相关资源
      最近更新 更多