在做WPF主题支持时,出现一个分组引起的莫名错误,可是折腾了我一番。在没有使用样式时,列表分组很正常,使用了别人写的ListBox列表样式后,发现GroupItem分组区没有内容,是空的,本篇把这一问题的解决过程给大家说一下,做主题时可以注意分组对列表样式的限制了。
ListBox增加分组
WPF为ItemsControl提供很多的样式扩展,要想实现列表分组也很简单,只需要做以下几步就可以了:
- 给列表控件增加分组样式
代码< Style x:Key = " GroupContainerStyle " TargetType = " {x:Type GroupItem} " >
< Setter Property = " Template " >
< Setter.Value >
< ControlTemplate TargetType = " {x:Type GroupItem} " >
< Expander IsExpanded = " True " >
< Expander.Header >
< Grid >
< Grid.ColumnDefinitions >
< ColumnDefinition Width = " Auto " />
< ColumnDefinition />
</ Grid.ColumnDefinitions >
< Grid.RowDefinitions >
< RowDefinition />
</ Grid.RowDefinitions >
< StackPanel Orientation = " Horizontal " Margin = " 0,0,10,0 " >
< TextBlock Text = " {Binding Path=Name} " FontWeight = " Bold " />
< TextBlock FontWeight = " Bold " Text = " {Binding Path=ItemCount, StringFormat=(共{0}条)} " />
</ StackPanel >
< Line Grid.Column = " 1 " SnapsToDevicePixels = " true " X1 = " 0 " X2 = " 1 " Stretch = " Fill " StrokeThickness = " 1 " />
</ Grid >
</ Expander.Header >
< ItemsPresenter />
</ Expander >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
GroupStyle gs = new GroupStyle();
gs.ContainerStyle = Application.Current.TryFindResource( " GroupContainerStyle " ) as Style;
lbModule.GroupStyle.Add(gs); 给数据增加分组
代码< UserControl.Resources >
< CollectionViewSource Source = " {x:Static oea:ApplicationModel.DefaultBusinessObjectInfos} " x:Key = " cvs " >
< CollectionViewSource.GroupDescriptions >
< PropertyGroupDescription PropertyName = " Catalog " />
</ CollectionViewSource.GroupDescriptions >
</ CollectionViewSource >
</ UserControl.Resources >
使用ListBox样式后
用了别人的一个ListBox样式文件,样式如下:
< Style TargetType = " {x:Type ListBox} " >
< Setter Property = " Background " Value = " {DynamicResource {x:Static SystemColors.WindowBrushKey}} " />
< Setter Property = " BorderBrush " >
< Setter.Value >
< LinearGradientBrush EndPoint = " 0.5,1 " StartPoint = " 0.5,0 " >
< GradientStop Color = " {DynamicResource PrimaryColor} " Offset = " 0 " />
< GradientStop Color = " {DynamicResource SecondaryColor} " Offset = " 1 " />
</ LinearGradientBrush >
</ Setter.Value >
</ Setter >
< Setter Property = " BorderThickness " Value = " 1 " />
< Setter Property = " Foreground " Value = " {DynamicResource {x:Static SystemColors.ControlTextBrushKey}} " />
< Setter Property = " ScrollViewer.HorizontalScrollBarVisibility " Value = " Auto " />
< Setter Property = " ScrollViewer.VerticalScrollBarVisibility " Value = " Auto " />
< Setter Property = " ScrollViewer.CanContentScroll " Value = " true " />
< Setter Property = " VerticalContentAlignment " Value = " Center " />
< Setter Property = " Template " >
< Setter.Value >
< ControlTemplate TargetType = " {x:Type ListBox} " >
< Border x:Name = " Bd " SnapsToDevicePixels = " true " Background = " {TemplateBinding Background} " BorderBrush = " {TemplateBinding BorderBrush} " BorderThickness = " {TemplateBinding BorderThickness} " Padding = " 1 " CornerRadius = " 4,4,4,4 " >
< Grid >
< ScrollViewer Padding = " {TemplateBinding Padding} " Focusable = " false " x:Name = " scrollViewer " >
< StackPanel Margin = " 2 " IsItemsHost = " true " />
<!--< ItemsPresenter SnapsToDevicePixels = " {TemplateBinding SnapsToDevicePixels} " />-->
</ ScrollViewer >
< Border CornerRadius = " 4,4,4,4 " Visibility = " Collapsed " x:Name = " border " Margin = " -2,-2,-2,-2 " >
< Border.Background >
< SolidColorBrush Color = " {DynamicResource DisabledColor} " />
</ Border.Background >
</ Border >
</ Grid >
</ Border >
< ControlTemplate.Triggers >
< Trigger Property = " IsEnabled " Value = " false " >
< Setter Property = " Visibility " TargetName = " border " Value = " Visible " />
</ Trigger >
< Trigger Property = " IsGrouping " Value = " true " >
< Setter Property = " ScrollViewer.CanContentScroll " Value = " false " />
</ Trigger >
</ ControlTemplate.Triggers >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
用完之后运行发现界面不对,点击分组标题后列表内容没有显示???
查找原因
自己想了一下,原因不明,无奈自己对WPF实现只了解一点,于是网上搜索ItemsPresenter empty,找到第一条网页ItemsPresenter + ItemsPanelTemplate vs Panel marked with IsItemsHost,进去后发现他提出了一个问题,就是在分组时如何取ItemsPresenter,发现Reflector工具可以看到以下代码:
代码internal static ItemsPresenter FromGroupItem(GroupItem groupItem)
{
if (groupItem == null )
{
return null ;
}
Visual parent = VisualTreeHelper.GetParent(groupItem) as Visual;
if (parent == null )
{
return null ;
}
return (VisualTreeHelper.GetParent(parent) as ItemsPresenter);
}
这个帖子上面也解释了为什么这么设计,我就不再重复了,原来在分组时对控件样式有要求,那就是控件样式必须存在ItemsPresenter。
确认原因
使用《WPF - Visual调试工具Snoop》工具查看一下,发现GroupItem下的ItemsPresenter是空的
切换回不使用样式再看看,发现在GroupItem之上有一个ItemsPresenter,而应用上面样式之后就没有了,果然就是样式文件的控件模板缺少ItemsPresenter的原因。
解决问题
原因知道了,解决问题也就非常简单了,修改样式表,主要就是把
<StackPanel Margin="2" IsItemsHost="true"/>
该为
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
修改后再次运行,界面正确,如下:
更多内容: 开源信息系统开发平台之OpenExpressApp框架.pdf
欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]