本文介绍了在 WPF ListBox 中对 ListItem 进行排序和分组 - GroupItem 折叠和展开的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对列表框项目进行排序和分组,为此我使用 CollectioView.

I sort and group listbox items, I use CollectioView on this purpose.

从视图模型类中,我在 ListBox ItemSource 属性上绑定集合,就是这样.

From view model class I bind collection on ListBox ItemSource property, here is it.

    public BindableCollection<UserInfo> Friends
    {
        get { return _friends; }
        set
        {
            _friends = value;
            NotifyOfPropertyChange(() => Friends);
        }
    }

ListBox items 是 UserInfo 的类型.

ListBox items is type of UserInfo.

当我初始化 ListBox 时,我使用此方法对项目进行排序和分组.

When I initialize ListBox I sort and group items with this method.

    private ICollectionView _currentView;

    //...

    private void SortContactList()
    {
        _currentView = CollectionViewSource.GetDefaultView(Friends);

        _currentView.GroupDescriptions.Add(new PropertyGroupDescription("TextStatus"));

        _currentView.SortDescriptions.Add(new SortDescription("TextStatus", ListSortDirection.Ascending));

        _currentView.SortDescriptions.Add(new SortDescription("Nick", ListSortDirection.Ascending));
    }

TextStatus 和 Nick 是 userInfo 类的属性.

TextStatus and Nick are properties of userInfo class.

我在 Listbox GroupStyle 中使用.这是它:

I use in Listbox GroupStyle. Here ist it:

    <Style x:Key="MessengerView_ToogleBtn" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Image x:Name="img" Source="/images/icons/Collapse.png" />
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="False">
                            <Setter TargetName="img" Property="Source" Value="/images/icons/Expand.png" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


   <GroupStyle>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="{x:Type GroupItem}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type GroupItem}">
                                    <ControlTemplate.Triggers>
                                        <DataTrigger Binding="{Binding Path=IsBottomLevel}" Value="True">
                                            <Setter TargetName="gridTemplate" Property="Grid.Background" Value="White" />
                                        </DataTrigger>
                                    </ControlTemplate.Triggers>
                                    <Grid>
                                        <Grid.RowDefinitions>
                                            <RowDefinition />
                                            <RowDefinition />
                                        </Grid.RowDefinitions>
                                        <Grid Background="Black"
                                                  x:Name="gridTemplate"
                                                  Height="26"
                                                  VerticalAlignment="Center">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="Auto" />
                                                <ColumnDefinition Width="100" />
                                                <ColumnDefinition Width="45" />
                                            </Grid.ColumnDefinitions>

                                            <ToggleButton x:Name="btnShowHide"
                                                          IsChecked="True"
                                                          Style="{StaticResource MessengerView_ToogleBtn}"/>

                                            <TextBlock Style="{StaticResource MessengerView_LbGroupHeader_TextBlock}"
                                                       Text="{Binding Path=Name}"
                                                       Grid.Column="1"/>
                                            <TextBlock TextAlignment="Left" Style="{StaticResource MessengerView_LbGroupHeader_TextBlock}"
                                                       Grid.Column="2"
                                                       Text="{Binding Path=ItemCount}"/>

                                        </Grid>

                                        <ItemsPresenter Visibility="{Binding ElementName=btnShowHide, Path=IsChecked,
                                                                            Converter={StaticResource booleanToVisibilityConverter}}"
                                                            Margin="3,3,3,3"
                                                            Grid.Row="1"  />

                                    </Grid>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>

如果我运行应用程序,它会显示在这张图片上.

If I run app, it look on this picture.

1.

我编辑 ListBox 的源属性,(添加、删除、更新),编辑完列表框后,我在 CollectionView 上调用 Refresh 方法.

I edit source property of ListBox, (add,remove, update), after edited listbox I call Refresh method on CollectionView.

            _currentView.Refresh();

问题是 GroupItem 是折叠的,我在所有 GroupItem 上调用 Refresh 方法展开.

Problem is that GroupItem is collapse and I call Refresh method on all GroupItem are expanded.

例如.

GroupItem 1 正在折叠.

GroupItem 1 is collapse.

GroupItem 2 已扩展.

GroupItem 2 is exapnded.

GroupItem 3 正在折叠.

GroupItem 3 is collapse.

调用Refresh ListBox前的样子如下图:

Before call Refresh ListBox look like on this picture:

我在 CollectionView 上调用 Refresh 方法并展开所有 GroupItems.我想保持原来的状态,怎么实现呢?

I call Refresh method on CollectionView and all GroupItems are expanded. I would like to keep the original state, how can I achive this?

调用 Refresh Lisbox 后看起来像在顶部的第一张图片.

After called Refresh Lisbox look like on first picture on the top.

推荐答案

解决方法并不完美.正如我所说,最好将 ViewModels 与您自己的分组一起使用,但这需要更多的代码.

The workaround isn't perfect. As I said, it is better to use ViewModels with your own grouping, but it will require much more code.

您需要两个事件处理程序:

You need two event handlers:

    private Dictionary<string, bool?> expandStates = new Dictionary<string, bool?>();

    private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        var grid = (Grid)sender;
        var dc = grid.DataContext as CollectionViewGroup;
        var groupName = (string)dc.Name;

        //If the dictionary contains the current group, retrieve a saved state of the group
        if (this.expandStates.ContainsKey(groupName))
        {
            var btn = (ToggleButton)grid.FindName("btnShowHide");
            btn.IsChecked = this.expandStates[groupName];
        } //Else add default state
        else this.expandStates.Add(groupName, true);

    }

    private void btnShowHide_Click(object sender, RoutedEventArgs e)
    {
        var btn = (ToggleButton)sender;
        var dc = (CollectionViewGroup)btn.DataContext;
        var groupName = (string)dc.Name;

        //Loaded event is fired earlier than the Click event, so I'm sure that the dictionary contains the key
        this.expandStates[groupName] = btn.IsChecked; //Save the current state
    }

它们在这里与控件绑定:

They are bound with controls here:

<ControlTemplate TargetType="{x:Type GroupItem}">
    <Grid Loaded="Grid_Loaded">

这里:

<ToggleButton x:Name="btnShowHide" Click="btnShowHide_Click" IsChecked="True" Margin="3.5" />

如果您在外部字典中的某处为 GroupItem 定义模板,则必须使用 UserControl 来访问代码隐藏.

If you define Template for GroupItem somewhere in an external dictionary, you must use UserControl for the purpose of having access to code-behind.

这篇关于在 WPF ListBox 中对 ListItem 进行排序和分组 - GroupItem 折叠和展开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-18 16:40