大连仟亿科技
客服中心
  • 电话
  • 电话咨询:0411-39943997
  • 手机
  • 手机咨询:15840979770
    手机咨询:13889672791
网络营销 >更多
您现在的位置:仟亿科技 > 新闻中心 > 常见问题

实现在ListView的GroupItem头中显示每列的Summary

作者:billionnet 发布于:2012/10/11 17:09:07 点击量:

 

问题描述

WPF自带的ListView和DataGrid控,都提供了数据分组的支持,并可以对分组的Header进行自定义。但是,如果想在每个分组的Header中,显示出本分组的"小计"就不是一件容易的事情了。

假设要用一个ListView用于显示全校学生成绩。按班级分组,并在分组头中显示班级平均分。

终终效果大致如下:

在ListView的GroupItem头中显示每列的Summary

图1. 在分组的Header中显示本分组的Aggregation

怎么样?有什么思路?实现的难点有:

  1. Group Header中的第一例显示为分组的名称。
  2. Group Header中的其它列与数据一致。
  3. Group Header中各列的宽度与ListView中列对应始终一致。
  4. Group Header 中各列的对齐方式与ListView中各列一致。

数据

Model层只有一个类,ScoreInfo,代码如下:

复制代码

public class ScoreInfo
{
public ScoreInfo(string studentNo, string className, int math, int english)
{
StudentNo = studentNo;
ClassName = className;
MathScore = math;
EnglishScore = english;
}

public string StudentNo { get; set; }

public string ClassName { get; set; }

public int MathScore { get; set; }

public int EnglishScore { get; set; }

[ReadOnly(true)]
public int TotalScore
{
get { return MathScore + EnglishScore; }
}
}

复制代码

一次考试中,学生的这些数据都不会变。所以不需要实现INotifyPropertyChanged接口。

DAL层直接返回假数据,代码如下:

复制代码

public class SchoolScoreProvider
{
public List ReadAllScoreInfo()
{
var random = new Random();
return (from i in Enumerable.Range(0, 4)
let className = String.Format("({0}) 班", i + 1)

from s in Enumerable.Range(i * 6 + 1, 6)
let mScore = random.Next(101)
let eScore = random.Next(101)

select new ScoreInfo(s.ToString(), className, mScore, eScore))
.ToList();
}
}

复制代码

在XAML中声明(实体化)数据源,代码如下:

复制代码



ObjectType="{x:Type l:SchoolScoreProvider}"
MethodName="ReadAllScoreInfo" />
Source="{StaticResource Data}">








复制代码

UI层代码

然后是ListView的定义:

复制代码

ItemsSource="{Binding}">











TextAlignment="Right" />






TextAlignment="Right" />






TextAlignment="Right" />





复制代码

为了让Group支持分列,直接能想到的方法就是在其中放置一个ListViewItem。经过尝试这个方案是可行的。需要自定义GroupItem的ControlTemplate。代码如下:

复制代码


复制代码

其中的关键点是,在里面放了一个ListViewItem。这里直接放GridViewRowPresenter也是可以正确显示出数据的,但是由于没有ListViewItem作Host,每列中的文字会始终向左对齐。

使用一个Converter,对当前组的数据进行Aggregation,生成一个表示班级平均分的ScoreInfo。Convert的代码如下:

复制代码

public class GroupDataAggregator : IValueConverter
{
public object Convert(object value, Type type, object arg, CultureInfo culture)
{
var groupData = value as CollectionViewGroup;
if (groupData != null)
{
var scores = groupData.Items.Cast();
var avgMath = (int)scores.Average(x => x.MathScore);
var avgEng = (int)scores.Average(x => x.EnglishScore);

return new ScoreInfo(groupData.Name.ToString(), null, avgMath, avgEng);
}

return new InvalidOperationException();
}

public object ConvertBack(object value, Type type, object arg, CultureInfo culture)
{
throw new NotImplementedException();
}
}

复制代码

当然,这个Convert并不重点。另一个重点是,要为GroupItem中的ListViewItem写一个特殊的Style,否则,什么东西都看不到。

复制代码





复制代码

关键的一步就是给GridViewRowPresenter指定Columns,ListView可不会自动为这个外人设置这个属性的。

再回去讲GroupItem,用于展开GroupItem的是其Template中的ToggleButton,即图中三角图标。其代码如下:

复制代码


复制代码

题外话

另给勤奋些、不喜欢吃冷饭的同学几个思考的方向,用于确认对上面代码的理解程度。

针对上面这个ToggleButton的Style:

  1. 每个Setter都有什么作用?删除每一个都有什么不同后果?哪些是可以删除的?(用时5分钟)
  2. 使用TemplateBinding与直接在ControlTemplate中写值有什么不同?(30秒)
  3. 为什么把BorderThickness绑定给了Path,而不是Border?(30秒)
  4. Style中的Trigger能否放在ControlTemplate.Triggers中?为什么使用Style Trigger而不是ControlTemplate Trigger?(5分钟)
  5. 如果你不会StreamGeometry中的语法,那么尝试解读StreamGeometry中的语法(其中Z表示曲线向原点闭合),并写出一个+ - 号风格的ToggleButton Style。(15分钟)

如果只是要方案。这里是完整的代码



分享到:


评论加载中...
内容:
评论者: 验证码:
  

Copyright@ 2011-2017 版权所有:大连仟亿科技有限公司 辽ICP备11013762-1号   google网站地图   百度网站地图   网站地图

公司地址:大连市沙河口区中山路692号辰熙星海国际2215 客服电话:0411-39943997 QQ:2088827823 42286563

法律声明:未经许可,任何模仿本站模板、转载本站内容等行为者,本站保留追究其法律责任的权利! 隐私权政策声明