我有一个Telerik Grid,它有一个需要显示列总和的页脚。但是,其中一个列的数据类型为TimeSpan
,Telerik的Sum聚合不支持。我需要使用GridBoundColumnBuilder.Aggregate()
来添加聚合。 所以我想基本上问题是如何在telerik的Aggregate()方法中引用我的自定义聚合。如果你发现其他任何我做错了,请随意指出:)使用{{ 3}},我为自定义聚合创建了一个类,名为SumAggregate
,如下所示。 (请注意,这还没有完成 - 它取自文章。它实际上实现了一个完全不同的聚合)
SumAggregate.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Telerik.Web.Mvc;
namespace TelerikPOC.CustomAggregates
{
public class SumAggregate : AggregateFunction
{
private System.Collections.Generic.List<object> distinctValues;
/// <summary>
/// Initializes the current aggregate function to its initial
/// state ready to accumulate and merge values.
/// </summary>
/// <remarks>
/// This method is called every time the accumulation of values
/// must start over for a new subset of records from the data source.
/// </remarks>
public void Init()
{
this.distinctValues = new System.Collections.Generic.List<object>();
}
/// <summary>
/// Accumulates new argument values to the current aggregate function.
/// </summary>
/// <remarks>
/// This aggregate function accepts one argument:
/// number - a numeric value to accumulate to the aggregate function;
/// </remarks>
public void Accumulate(object[] values)
{
if (!distinctValues.Contains(values[0]))
{
distinctValues.Add(values[0]);
}
}
/// <summary>
/// Merges the specified aggregate function to the current one.
/// </summary>
/// <param name="Aggregate">
/// Specifies an aggregate function to be merged to the current one.
/// </param>
/// <remarks>
/// This method allows the reporting engine to merge two accumulated
/// subsets of the same aggregate function into a single result.
/// </remarks>
public void Merge(AggregateFunction aggregate)
{
// Accumulate the values of the specified aggregate function.
System.Collections.Generic.List<object> sums1 = ((SumAggregate)aggregate).distinctValues;
foreach (object o in sums1)
{
this.Accumulate(new object[] { o });
}
}
/// <summary>
/// Returns the currently accumulated value of the aggregate function.
/// </summary>
/// <returns>
/// The currently accumulated numeric value of the aggregate function.
/// </returns>
public object GetValue()
{
return this.distinctValues.Count;
}
}
}
这是添加聚合的代码。这与 index.cshtml 中的代码冲突,但我想包括两种添加聚合的方法,只是为了给出答案的更多选项。这需要修改为使用自定义聚合而不是内置聚合,就像它现在使用的那样。
GridHelper.cs (未完成 - 将添加逻辑以循环遍历列等等。顺便说一下,如果有人愿意帮助我 我也会非常感激,不过我承认我还没有尝试过任何东西。)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Telerik.Web.Mvc.UI.Fluent;
using TelerikPOC.CustomAggregates;
namespace TelerikPOC.Helpers
{
public class GridHelper
{
public static void AddAggregateToColumn(GridBoundColumnBuilder<dynamic> columnBuilder, string Aggregate)
{
switch (Aggregate)
{
case "Sum":
{
columnBuilder.Aggregate(aggregates => aggregates.Sum())
.GroupFooterTemplate(result => "Sum:" + result.Sum)
.ClientFooterTemplate("Sum: <#= Sum #>")
.FooterTemplate(result => "Total: " + result.Sum);
}
break;
}
}
}
}
然后我使用HtmlHelper
类来构建/渲染telerik网格,如下所示:
来自 Index.cshtml :(请务必阅读右侧的评论)
@{
Html.Telerik()
.Grid(Model)
.Name("statisticalGrid")
.Columns(columns =>
{
columns.Bound(o => o.PlanID).Aggregate(something); //This is probably going to be where
columns.Bound(o => o.SessionID).Aggregate(something); //I need the help. Just not sure
columns.Bound(o => o.TimeSpan).Aggregate(something); //how to reference the custom
columns.Bound(o => o.TimeSpanDouble).Aggregate(something); //aggregate here, in
}) //place of `something`
.Sortable(sortable => sortable.Enabled(true))
.Filterable()
.Pageable(page => page.PageSize(25))
.Reorderable(reorder => reorder.Columns(true))
.Groupable(groupable => groupable.Enabled(true))
.ClientEvents(events => events
.OnColumnReorder("onReorder"))
.Render();
}
所以我想基本上问题是如何在telerik的Aggregate()
方法中引用我的自定义聚合。如果你发现其他任何我做错了,请随意指出:)
编辑:注意到我必须在SumAggregate类中实现方法CreateAggregateExpression(Expression, bool)
。但不完全确定如何实现它。
上次编辑:我使用自定义列构建器方法来构建columms,因此我不确定如何在此处进行格式化。我能够格式化总和,但不能格式化列的其余部分,因为在telerik调用的上下文之外,我无法访问item
变量。这基本上就是我的列构建逻辑:
在telerik代码中,
.Columns(a => GridHelper.GenerateColumns(a, Model.SelectedReport))
生成列类似于:
public static void GenerateColumns(GridColumnFactory<dynamic> columnFactory, Company.Project.Data.Entity.Report reportStructure)
{
foreach (var columnLayout in reportStructure.ReportCols.OrderBy(o => o.ColumnSequence))
{
GridBoundColumnBuilder<dynamic> columnBuilder = columnFactory.Bound(columnLayout.ColumnType);
//do other stuff here (add aggregates, formatting, etc)
}
那么我将如何在此上下文中进行格式化?
答案 0 :(得分:5)
您可以做的一件事是在“Days”中添加另一个代表TimeSpan的列。然后,您不必使用自定义聚合。
型号:
public List<Objects.Temp> GetTemp()
{
List<Objects.Temp> ltemp = new List<Objects.Temp>();
System.Random r = new Random();
Objects.Temp t = new Objects.Temp();
t.Name = "One";
t.start = DateTime.Now;
t.Value = r.NextDouble();
t.ts = DateTime.Today.AddDays(25) - t.start;
t.tsDays = t.ts.Days;
ltemp.Add(t);
t = new Objects.Temp();
t.Name = "Two";
t.start = DateTime.Now;
t.Value = r.NextDouble();
t.ts = DateTime.Today.AddDays(15) - t.start;
t.tsDays = t.ts.Days;
ltemp.Add(t);
t = new Objects.Temp();
t.Name = "Three";
t.start = DateTime.Now;
t.Value = r.NextDouble();
t.ts = DateTime.Today.AddDays(55) - t.start;
t.tsDays = t.ts.Days;
ltemp.Add(t);
return ltemp;
}
查看:
@(Html.Telerik().Grid(Model)
.Name("Grid")
.Columns(columns =>
{
columns.Bound(o => o.Name)
.Aggregate(aggregates => aggregates.Count())
.FooterTemplate(@<text>Total Count: @item.Count</text>)
.GroupFooterTemplate(@<text>Count: @item.Count</text>);
columns.Bound(o => o.start)
.Width(200)
.Aggregate(aggreages => aggreages.Max())
//.Format("{0:c}")
.FooterTemplate(@<text>Max: @item.Max</text>)
.GroupFooterTemplate(@<text>Max: @item.Max</text>);
columns.Bound(o => o.Value)
.Width(200)
.Aggregate(aggregates => aggregates.Average())
.FooterTemplate(@<text>Average: @item.Average</text>)
.GroupFooterTemplate(@<text>Average: @item.Average</text>);
columns.Bound(o => o.ts)
.Width(100)
.Aggregate(aggregates => aggregates.Count().Min().Max())
.FooterTemplate(
@<text>
<div>Min: @item.Min</div>
<div>Max: @item.Max</div>
</text>)
.GroupHeaderTemplate(@<text>@item.Title: @item.Key (Count: @item.Count)</text>);
columns.Bound(o => o.tsDays)
.Width(100)
.Aggregate(aggregates => aggregates.Sum())
.FooterTemplate(
@<text>
<div>Sum: @item.Sum Days</div>
</text>)
.GroupHeaderTemplate(@<text>@item.Title: @item.Key (Sum: @item.Sum)</text>);
})
.Sortable()
)
你得到的东西看起来像这样:
版本2
我更新了我的答案,以便只有一个TimeSpan列与TimeSpan相加并以TimeSpan格式显示它。列中的数据实际上是TimeSpan.TotalMilliseconds,但它使用模板显示为TimeSpan,并使用TimeSpan.FromMilliseconds方法格式化TimeSpan。我认为这样做比创建自定义聚合类更容易,如果甚至可以使用MVC扩展。
型号:
public class Temp
{
public string Name { get; set; }
public DateTime Start { get; set; }
public double Value { get; set; }
public TimeSpan ts { get; set; }
public double tsMilliseconds { get; set; }
}
List<Objects.Temp> ltemp = new List<Objects.Temp>();
System.Random r = new Random();
Objects.Temp t = new Objects.Temp();
t.Name = "One";
t.Start = DateTime.Now;
t.Value = r.NextDouble();
t.ts = DateTime.Today.AddDays(25) - t.Start;
t.tsMilliseconds = t.ts.TotalMilliseconds;
ltemp.Add(t);
t = new Objects.Temp();
t.Name = "Two";
t.Start = DateTime.Now;
t.Value = r.NextDouble();
t.ts = DateTime.Today.AddDays(15) - t.Start;
t.tsMilliseconds = t.ts.TotalMilliseconds;
ltemp.Add(t);
t = new Objects.Temp();
t.Name = "Three";
t.Start = DateTime.Now;
t.Value = r.NextDouble();
t.ts = DateTime.Today.AddDays(55) - t.Start;
t.tsMilliseconds = t.ts.TotalMilliseconds;
ltemp.Add(t);
查看:
@(Html.Telerik().Grid(Model)
.Name("Grid")
.Columns(columns =>
{
columns.Bound(o => o.Name)
.Aggregate(aggregates => aggregates.Count())
.FooterTemplate(@<text>Total Count: @item.Count</text>)
.GroupFooterTemplate(@<text>Count: @item.Count</text>);
columns.Bound(o => o.Start)
.Template(@<text>@item.Start.ToShortDateString()</text>)
.Aggregate(aggreages => aggreages.Max())
.FooterTemplate(@<text>Max: @item.Max.Format("{0:d}")</text>)
.GroupHeaderTemplate(@<text>Max: @item.Max.Format("{0:d}")</text>)
.GroupFooterTemplate(@<text>Max: @item.Max.Format("{0:d}")</text>);
columns.Bound(o => o.Value)
.Width(200)
.Aggregate(aggregates => aggregates.Average())
.FooterTemplate(@<text>Average: @item.Average</text>)
.GroupFooterTemplate(@<text>Average: @item.Average</text>);
columns.Bound(o => o.tsMilliseconds)
.Width(100)
.Aggregate(aggregates => aggregates.Sum())
.Template(@<text>@TimeSpan.FromMilliseconds(@item.tsMilliseconds)</text>)
.Title("TimeSpan")
.FooterTemplate(
@<text>
<div>Sum: @TimeSpan.FromMilliseconds( @Convert.ToDouble( @item.Sum.Value.ToString() ) ) </div>
</text>)
//header if you group by TimeSpan
.GroupHeaderTemplate(@<text>@item.Title: @item.Key (Sum: @TimeSpan.FromMilliseconds(@Convert.ToDouble(@item.Sum.Value.ToString())))</text>)
//footer for grouping
.GroupFooterTemplate(@<text>Sum: @TimeSpan.FromMilliseconds(@Convert.ToDouble(@item.Sum.Value.ToString()))</text>);
})
.Sortable()
.Groupable(settings => settings.Groups(groups => groups.Add(o => o.Start)))
)
没有分组产生这个:
通过分组产生: