4

我有一个 Telerik Grid,它有一个需要显示列总和的页脚。但是,列的数据类型之一是TimeSpanTelerik 的 Sum 聚合不支持。我需要使用GridBoundColumnBuilder.Aggregate()来添加聚合。所以我想基本上问题是如何在 Telerik 的 Aggregate() 方法中引用我的自定义聚合。如果您发现我做错了什么,请随时指出 :) 使用这篇文章,我为我的自定义聚合创建了一个类,名为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()方法中引用我的自定义聚合。如果您发现我做错了什么,请随时指出:)

编辑:刚刚注意到我必须CreateAggregateExpression(Expression, bool)在 SumAggregate 类中实现该方法。不过,不完全确定如何实现它。

最后编辑:我使用自定义列构建器方法来构建列,所以我不确定如何在这里进行格式化。我能够格式化总和,但不能格式化列的其余部分,因为在 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)
            }

那么在这种情况下我将如何进行格式化呢?

4

1 回答 1

5

您可以做的一件事是在“天”中添加另一个表示 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)))
) 

没有分组会产生这个:

时间跨度聚合

随着分组产生这个:

带分组

于 2012-06-11T23:17:11.853 回答