4

列の合計を表示する必要があるフッターを持つTelerikグリッドがあります。ただし、列のデータ型の1つはですTimeSpan。これはTelerikの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

できることの1つは、「日」で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列が1つだけになるように、回答を更新しました。列のデータは実際にはTimeSpan.TotalMillisecondsですが、テンプレートを使用し、TimeSpan.FromMillisecondsメソッドを使用してTimeSpanをフォーマットすると、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)))
) 

グループ化せずにこれを生成します:

TimeSpan Aggregate

グループ化すると、次のようになります。

グループ化あり

于 2012-06-11T23:17:11.853 に答える