WPF - Group分组对ListBox等列表样式的约束

原文: WPF - Group分组对ListBox等列表样式的约束

  在做WPF主题支持时,出现一个分组引起的莫名错误,可是折腾了我一番。在没有使用样式时,列表分组很正常,使用了别人写的ListBox列表样式后,发现GroupItem分组区没有内容,是空的,本篇把这一问题的解决过程给大家说一下,做主题时可以注意分组对列表样式的限制了。

ListBox增加分组

  WPF为ItemsControl提供很多的样式扩展,要想实现列表分组也很简单,只需要做以下几步就可以了:

  1. 给列表控件增加分组样式
    代码
         
         
    < 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);
  2. 给数据增加分组

    代码
         
         
    < 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/ ]

猜你喜欢

转载自www.cnblogs.com/lonelyxmas/p/9473000.html