Custom Aggregate Function

Stimulsoft Reports.NET discussion
Post Reply
casic
Posts: 68
Joined: Thu Jan 18, 2007 4:25 pm
Location: Germany

Custom Aggregate Function

Post by casic »

Hi there,

I wrote the following custom aggregate function to concatenate the expression results of a databand:

Code: Select all

 /// <summary>
 /// Concats the expression by using a delimiter.
 /// </summary>
 public class ConcatFunctionService : StiAggregateFunctionService
 {
  private string _summary = String.Empty;
  private string _delimiter = ", ";

  /// <summary>
  /// Gets value, indicates that this function require a parameter.
  /// </summary>
  public override bool RecureParam
  {
   get
   {
    return true;
   }
  }

  /// <summary>
  /// Gets a service name.
  /// </summary>
  public override string ServiceName
  {
   get
   {
    return "Concat";
   }
  }

  /// <summary>
  /// Constructor.
  /// </summary>
  /// <param name="runningTotal">true to running total.</param>
  public ConcatFunctionService(bool runningTotal)
   : base(runningTotal)
  {
  }

  /// <summary>
  /// Constructor.
  /// </summary>
  /// <param name="runningTotal">true to running total.</param>
  /// <param name="delimiter">Delimiter.</param>
  public ConcatFunctionService(bool runningTotal, string delimiter)
   : base(runningTotal)
  {
   _delimiter = delimiter;
  }

  /// <summary>
  /// Default constructor.
  /// </summary>
  public ConcatFunctionService()
  {
  }

  /// <summary>
  /// A value calculation.
  /// </summary>
  /// <param name="value">Value.</param>
  public override void CalcItem(object value)
  {
   if (value == null || value == DBNull.Value)
   {
    return;
   }
   if (!String.IsNullOrEmpty(this._summary)) this._summary += this._delimiter;
   this._summary = this._summary + Convert.ToString(value);
  }

  /// <summary>
  /// Returns the type of the result.
  /// </summary>
  public override Type GetResultType()
  {
   return typeof(string);
  }

  /// <summary>
  /// Returns the calculation result.
  /// </summary>
  /// <returns>Calculation result.</returns>
  public override object GetValue()
  {
   return this._summary;
  }

  /// <summary>
  /// First initialization.
  /// </summary>
  public override void Init()
  {
   if (!base.RunningTotal || this.IsFirstInit)
   {
    this._summary = String.Empty;
   }
  }

  /// <summary>
  /// Restores the earlier saved object state.
  /// </summary>
  /// <param name="stateName">A name of the state being restored.</param>
  public override void RestoreState(string stateName)
  {
   if (base.States.IsExist(stateName, this))
   {
    this._summary = Convert.ToString(base.States.Pop(stateName, this, "summary"));
   }
  }

  /// <summary>
  /// Saves the current state of an object.
  /// </summary>
  /// <param name="stateName">A name of the state being saved.</param>
  public override void SaveState(string stateName)
  {
   base.States.Push(stateName, this, "summary", this._summary);
  }

  /// <summary>
  /// Sets the calculation result.
  /// </summary>
  public override void SetValue(object value)
  {
   this._summary = Convert.ToString(value);
  }
 }
I added the service to the report system as following:

Code: Select all

StiOptions.Services.AggregateFunctions.Add(new ConcatFunctionService());
Now I can use the Concat function in the report which works very well, as long as I specify only the databand and expression.
If I specify the additional delimiter parameter, the Concat aggregate function no longer works :?

Working:

Code: Select all

{Concat(DataAddress,Address.FirstName)}
NOT working:

Code: Select all

{Concat(DataAddress,Address.FirstName,false,"-")}
So, what I'm missing here? What I have to declare so I can use additional parameters in the aggregate function?

Thank you very much for your support in advance,

Kind regards,

Markus
Alex K.
Posts: 6488
Joined: Thu Jul 29, 2010 2:37 am

Re: Custom Aggregate Function

Post by Alex K. »

Hello,

Unfortunately, due to the serialization and compilation abilities, all functions may use maximum is two parameters.
As a way, you can try to use the following function:

Code: Select all

{Func.EngineHelper.JoinColumnContent(datasource, "fieldName", "delimiter")}
Thank you.
casic
Posts: 68
Joined: Thu Jan 18, 2007 4:25 pm
Location: Germany

Re: Custom Aggregate Function

Post by casic »

Hello Aleksey,

thank you very much for your solution suggestion. The main difference between your solution and using an aggregate function is that the static function use a datasource (in it's current state) and the aggregate function a databand. If there are more than one databand using the same datasource, differences can occur. So I prefer the aggregate function approach. Also, I can use expressions with aggregate functions instead of strings :-)

I added the ConcatByTabFunctionService (derivered from the ConcatFunctionService above) which use the tab character as delimiter. So I can replace the result with the delimiter I would like to use:

Code: Select all

{Replace(ConcatByTab(DataAddress,Address.FirstName),"\t", ", ")}
Thank you very much for your support,

Kind regards,

Markus
Alex K.
Posts: 6488
Joined: Thu Jul 29, 2010 2:37 am

Re: Custom Aggregate Function

Post by Alex K. »

Hello

We are always glad to help you!
Please let us know if you need any additional help.

Thank you.
Post Reply