Как получить доступ к элементу в шаблоне WPF GroupItem - PullRequest
0 голосов
/ 29 августа 2018

У меня есть 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) Но всегда возвращается пустая коллекция

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

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018

Странно , ответ @ mm8 не сработал, и я не мог понять, почему. Но в любом случае мне удалось сделать обходной путь. Ключ заключается в том, чтобы связать свойство IsExpanded расширителя с неиспользуемым свойством ListView, например, его тег:

<ControlTemplate>
    <Expander Header="{Binding Name}">
        <Expander.IsExpanded>
            <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=ListView}" Path="Tag" />
        </Expander.IsExpanded>
        <ItemsPresenter />
    </Expander>
</ControlTemplate>

и затем вы можете управлять свойством IsExpanded для всех из них, установив lv.Tag = true; или lv.Tag = false; в коде.

0 голосов
/ 29 августа 2018

Вы можете найти элементы Expander в визуальном дереве с помощью рекурсивного метода и класса VisualTreeHelper:

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

Редактировать: Если вы хотите сделать это, как только вы установите свойство ItemsSource для ListView, вам нужно подождать, пока контейнеры не будут созданы. Обработка события 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;
        }
    };
}
...