在《内置支持的列表编辑方式》中介绍了OpenExpressApp内置的列表编辑方式。由于在列表显示过程中,经常会遇到需要分组显示的需求,所以OEA也内置了列表分组功能(暂时还不支持多对象树分组),与框架结合起来,完成这个功能更简单友好。本篇介绍一下OEA对列表分组的支持。
界面
设置分组后,AutoUI自动生成如下所示界面:每一组之上显示一条记录,左边为上下箭头,点击后可以展开和折叠分组的内容,右边显示分组依据属性和当前分组的条目数目。
类库编写
只需要在显示对象类型定义的BusinessObjectAttribute加上属性PropertyGroup,系统支持多个分组, 属性值为一个带分隔符‘;’的属性名称字符串列表,AutoUI会自动根据分组属性来构建列表界面,显示结果如上图所示,以下为代码片段:
[BusinessObject(ModuleType
=
ModuleType.List,
PropertyGroup
=
"
ProjectName
"
), Label(
"
清单查询
"
)]
public partial class SingleBq : GBusinessBase < SingleBq >
{
public string ProjectName
{
get
{
return ProjectInfo.Name;
}
}
}
public partial class SingleBq : GBusinessBase < SingleBq >
{
public string ProjectName
{
get
{
return ProjectInfo.Name;
}
}
}
分组样式文件
参考了《WPF - DataGrid 相关收集》中的WPF DataGrid Practical Examples,这个例子列举了很多微软DataGrid的使用,分组是参考Style完全版的那个页面中的Group样式而完成的。如果想学习这个,大家必须先对样式文件、WPF的分组有所了解,网上这类文章也很多,这里也不重复了。以下为样式:
Code
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- style the expander toggle button -->
<ControlTemplate x:Key="ExpanderToggleButton" TargetType="ToggleButton">
<Border>
<Path Name="Arrow" Fill="Black" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="M 0 0 L 6 8 L 12 0 Z"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="Arrow" Property="Data" Value="M 0 8 L 6 0 L 12 8 Z" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- expander styled to give a full width header and to provide access to the toggle button -->
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Name="ContentRow" Height="0"/>
</Grid.RowDefinitions>
<Border Name="Border" Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ToggleButton IsChecked="{Binding Path=IsExpanded,Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True" Template="{StaticResource ExpanderToggleButton}" />
<ContentPresenter Grid.Column="1" Margin="4" ContentSource="Header" RecognizesAccessKey="True" />
</Grid>
</Border>
<Border Name="Content" Grid.Row="1" Background="Transparent" BorderThickness="0">
<ContentPresenter Margin="3,0,0,0" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ContentRow" Property="Height" Value="{Binding ElementName=Content, Path=DesiredHeight}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- a grouping style that uses an expander to render the rouped data -->
<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>
</ResourceDictionary>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- style the expander toggle button -->
<ControlTemplate x:Key="ExpanderToggleButton" TargetType="ToggleButton">
<Border>
<Path Name="Arrow" Fill="Black" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="M 0 0 L 6 8 L 12 0 Z"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="Arrow" Property="Data" Value="M 0 8 L 6 0 L 12 8 Z" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- expander styled to give a full width header and to provide access to the toggle button -->
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Name="ContentRow" Height="0"/>
</Grid.RowDefinitions>
<Border Name="Border" Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ToggleButton IsChecked="{Binding Path=IsExpanded,Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True" Template="{StaticResource ExpanderToggleButton}" />
<ContentPresenter Grid.Column="1" Margin="4" ContentSource="Header" RecognizesAccessKey="True" />
</Grid>
</Border>
<Border Name="Content" Grid.Row="1" Background="Transparent" BorderThickness="0">
<ContentPresenter Margin="3,0,0,0" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ContentRow" Property="Height" Value="{Binding ElementName=Content, Path=DesiredHeight}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- a grouping style that uses an expander to render the rouped data -->
<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>
</ResourceDictionary>
OpenExpressApp对分组支持的实现
- 元信息支持分组支持
[AttributeUsage(AttributeTargets.Class)]
public class BusinessObjectAttribute : Attribute
{
// 默认分组
public string PropertyGroup { get ; set ; }
} - 业务模型增加GroupDescriptions
/// <summary>
/// 业务对象模型
/// </summary>
public class BusinessObjectInfo
{
/// 默认分组属性值
public string [] GroupDescriptions;
public BusinessObjectInfo(Type boType)
{
this .BOType = boType;
BusinessObjectAttribute = boType.GetSingleAttribute < BusinessObjectAttribute > ();
if ( ! String.IsNullOrEmpty(BusinessObjectAttribute.PropertyGroup))
GroupDescriptions = BusinessObjectAttribute.PropertyGroup.Split( ' ; ' );
}
}
- 把上面的样式存为文件Resource.xaml,在系统模块ExpressAppWPFModule的初始化方法中增加装载样式文件,代码如下:
resouceDic = Application.LoadComponent( new Uri( " OpenExpressApp.Module.WPF;component/Resources/Resource.xaml " , UriKind.Relative)) as ResourceDictionary;
Application.Current.Resources.MergedDictionaries.Insert( 0 , resouceDic); - 增加以前的AutoUI.CreateListControl代码,设置GroupStyle
public static object CreateListControl(Type boType, ListObjectView view)
{
DataGrid dg = new SelectionDataGrid()
{
CanUserAddRows = false ,
AutoGenerateColumns = false ,
VerticalGridLinesBrush = new SolidColorBrush(Colors.Gray),
HorizontalGridLinesBrush = new SolidColorBrush(Colors.Gray),
};
GroupStyle gs = new GroupStyle();
gs.ContainerStyle = Application.Current.TryFindResource( " GroupContainerStyle " ) as Style;
dg.GroupStyle.Add(gs);
...
}
- 修改ListEditor.OnSetData,设置collectionView.GroupDescriptions
public virtual void OnSetData()
{
ICollectionView collectionView = CollectionViewSource.GetDefaultView(View.Data);
if ( null != collectionView)
{
string [] groups = ApplicationModel.GetBusinessObjectInfo(BOType).GroupDescriptions;
if ( null != groups)
{
foreach ( string propertyName in groups)
collectionView.GroupDescriptions.Add( new PropertyGroupDescription(propertyName));
}
}
dg.ItemsSource = collectionView;
}