问题描述
我对列表框项目进行排序和分组,为此我使用 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 折叠和展开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!