FastReport
457 строк · 14.1 Кб
1using System.ComponentModel;2using FastReport.Utils;3using FastReport.Data;4using System.Drawing.Design;5
6namespace FastReport7{
8/// <summary>9/// Specifies a sort order.10/// </summary>11/// <remarks>12/// This enumeration is used in the group header and in the "Matrix" object.13/// </remarks>14public enum SortOrder15{16/// <summary>17/// Specifies no sort (natural order).18/// </summary>19None,20
21/// <summary>22/// Specifies an ascending sort order.23/// </summary>24Ascending,25
26/// <summary>27/// Specifies a descending sort order.28/// </summary>29Descending
30}31
32/// <summary>33/// Represents a group header band.34/// </summary>35/// <remarks>36/// A simple group consists of one <b>GroupHeaderBand</b> and the <b>DataBand</b> that is set37/// to the <see cref="Data"/> property. To create the nested groups, use the <see cref="NestedGroup"/> property.38/// <note type="caution">39/// Only the last nested group can have data band.40/// </note>41/// <para/>Use the <see cref="Condition"/> property to set the group condition. The <see cref="SortOrder"/>42/// property can be used to set the sort order for group's data rows. You can also use the <b>Sort</b>43/// property of the group's <b>DataBand</b> to specify additional sort.44/// </remarks>45/// <example>This example shows how to create nested groups.46/// <code>47/// ReportPage page = report.Pages[0] as ReportPage;48///49/// // create the main group50/// GroupHeaderBand mainGroup = new GroupHeaderBand();51/// mainGroup.Height = Units.Millimeters * 10;52/// mainGroup.Name = "MainGroup";53/// mainGroup.Condition = "[Orders.CustomerName]";54/// // add a group to the page55/// page.Bands.Add(mainGroup);56///57/// // create the nested group58/// GroupHeaderBand nestedGroup = new GroupHeaderBand();59/// nestedGroup.Height = Units.Millimeters * 10;60/// nestedGroup.Name = "NestedGroup";61/// nestedGroup.Condition = "[Orders.OrderDate]";62/// // add it to the main group63/// mainGroup.NestedGroup = nestedGroup;64///65/// // create a data band66/// DataBand dataBand = new DataBand();67/// dataBand.Height = Units.Millimeters * 10;68/// dataBand.Name = "GroupData";69/// dataBand.DataSource = report.GetDataSource("Orders");70/// // connect the databand to the nested group71/// nestedGroup.Data = dataBand;72/// </code>73/// </example>74public partial class GroupHeaderBand : HeaderFooterBandBase75{76#region Fields77private GroupHeaderBand nestedGroup;78private DataBand data;79private GroupFooterBand groupFooter;80private DataHeaderBand header;81private DataFooterBand footer;82private string condition;83private SortOrder sortOrder;84private bool keepTogether;85private bool resetPageNumber;86private object groupValue;87#endregion88
89#region Properties90/// <summary>91/// Gets or sets a nested group.92/// </summary>93/// <remarks>94/// Use this property to create nested groups.95/// <note type="caution">96/// Only the last nested group can have data band.97/// </note>98/// </remarks>99/// <example>100/// This example demonstrates how to create a group with nested group.101/// <code>102/// ReportPage page;103/// GroupHeaderBand group = new GroupHeaderBand();104/// group.NestedGroup = new GroupHeaderBand();105/// group.NestedGroup.Data = new DataBand();106/// page.Bands.Add(group);107/// </code>108/// </example>109[Browsable(false)]110public GroupHeaderBand NestedGroup111{112get { return nestedGroup; }113set114{115SetProp(nestedGroup, value);116nestedGroup = value;117}118}119
120/// <summary>121/// Gets or sets the group data band.122/// </summary>123/// <remarks>124/// Use this property to add a data band to a group. Note: only the last nested group can have Data band.125/// </remarks>126/// <example>127/// This example demonstrates how to add a data band to a group.128/// <code>129/// ReportPage page;130/// GroupHeaderBand group = new GroupHeaderBand();131/// group.Data = new DataBand();132/// page.Bands.Add(group);133/// </code>134/// </example>135[Browsable(false)]136public DataBand Data137{138get { return data; }139set140{141SetProp(data, value);142data = value;143}144}145
146/// <summary>147/// Gets or sets a group footer.148/// </summary>149[Browsable(false)]150public GroupFooterBand GroupFooter151{152get { return groupFooter; }153set154{155SetProp(groupFooter, value);156groupFooter = value;157}158}159
160/// <summary>161/// Gets or sets a header band.162/// </summary>163[Browsable(false)]164public DataHeaderBand Header165{166get { return header; }167set168{169SetProp(header, value);170header = value;171}172}173
174/// <summary>175/// Gets or sets a footer band.176/// </summary>177/// <remarks>178/// To access a group footer band, use the <see cref="GroupFooter"/> property.179/// </remarks>180[Browsable(false)]181public DataFooterBand Footer182{183get { return footer; }184set185{186SetProp(footer, value);187footer = value;188}189}190
191/// <summary>192/// Gets or sets the group condition.193/// </summary>194/// <remarks>195/// This property can contain any valid expression. When running a report, this expression is calculated196/// for each data row. When the value of this condition is changed, FastReport starts a new group.197/// </remarks>198[Category("Data")]199[Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]200public string Condition201{202get { return condition; }203set { condition = value; }204}205
206/// <summary>207/// Gets or sets the sort order.208/// </summary>209/// <remarks>210/// FastReport can sort data rows automatically using the <see cref="Condition"/> value.211/// </remarks>212[DefaultValue(SortOrder.Ascending)]213[Category("Behavior")]214public SortOrder SortOrder215{216get { return sortOrder; }217set { sortOrder = value; }218}219
220/// <summary>221/// Gets or sets a value indicating that the group should be printed together on one page.222/// </summary>223[DefaultValue(false)]224[Category("Behavior")]225public bool KeepTogether226{227get { return keepTogether; }228set { keepTogether = value; }229}230
231/// <summary>232/// Gets or sets a value that determines whether to reset the page numbers when this group starts print.233/// </summary>234/// <remarks>235/// Typically you should set the <see cref="BandBase.StartNewPage"/> property to <b>true</b> as well.236/// </remarks>237[DefaultValue(false)]238[Category("Behavior")]239public bool ResetPageNumber240{241get { return resetPageNumber; }242set { resetPageNumber = value; }243}244
245internal DataSourceBase DataSource246{247get248{249DataBand dataBand = GroupDataBand;250return dataBand == null ? null : dataBand.DataSource;251}252}253
254internal DataBand GroupDataBand255{256get257{258GroupHeaderBand group = this;259while (group != null)260{261if (group.Data != null)262return group.Data;263group = group.NestedGroup;264}265return null;266}267}268#endregion269
270#region IParent271/// <inheritdoc/>272public override void GetChildObjects(ObjectCollection list)273{274base.GetChildObjects(list);275if (!IsRunning)276{277list.Add(header);278list.Add(nestedGroup);279list.Add(data);280list.Add(groupFooter);281list.Add(footer);282}283}284
285/// <inheritdoc/>286public override bool CanContain(Base child)287{288return base.CanContain(child) ||289(child is DataBand && nestedGroup == null && data == null) ||290(child is GroupHeaderBand && (nestedGroup == null || nestedGroup is GroupHeaderBand) && data == null) ||291child is GroupFooterBand || child is DataHeaderBand || child is DataFooterBand;292}293
294/// <inheritdoc/>295public override void AddChild(Base child)296{297if (IsRunning)298{299base.AddChild(child);300return;301}302
303if (child is GroupHeaderBand)304NestedGroup = child as GroupHeaderBand;305else if (child is DataBand)306Data = child as DataBand;307else if (child is GroupFooterBand)308GroupFooter = child as GroupFooterBand;309else if (child is DataHeaderBand)310Header = child as DataHeaderBand;311else if (child is DataFooterBand)312Footer = child as DataFooterBand;313else314base.AddChild(child);315}316
317/// <inheritdoc/>318public override void RemoveChild(Base child)319{320base.RemoveChild(child);321if (IsRunning)322return;323
324if (child is GroupHeaderBand && nestedGroup == child)325NestedGroup = null;326if (child is DataBand && data == child as DataBand)327Data = null;328if (child is GroupFooterBand && groupFooter == child)329GroupFooter = null;330if (child is DataHeaderBand && header == child)331Header = null;332if (child is DataFooterBand && footer == child)333Footer = null;334}335#endregion336
337#region Public Methods338/// <inheritdoc/>339public override void Assign(Base source)340{341base.Assign(source);342
343GroupHeaderBand src = source as GroupHeaderBand;344Condition = src.Condition;345SortOrder = src.SortOrder;346KeepTogether = src.KeepTogether;347ResetPageNumber = src.ResetPageNumber;348}349
350/// <inheritdoc/>351public override void Serialize(FRWriter writer)352{353GroupHeaderBand c = writer.DiffObject as GroupHeaderBand;354base.Serialize(writer);355if (writer.SerializeTo == SerializeTo.Preview)356return;357
358if (Condition != c.Condition)359writer.WriteStr("Condition", Condition);360if (SortOrder != c.SortOrder)361writer.WriteValue("SortOrder", SortOrder);362if (KeepTogether != c.KeepTogether)363writer.WriteBool("KeepTogether", KeepTogether);364if (ResetPageNumber != c.ResetPageNumber)365writer.WriteBool("ResetPageNumber", ResetPageNumber);366}367
368/// <inheritdoc/>369public override string[] GetExpressions()370{371return new string[] { Condition };372}373
374internal override bool IsEmpty()375{376if (NestedGroup != null)377return NestedGroup.IsEmpty();378else if (Data != null)379return Data.IsEmpty();380return base.IsEmpty();381}382
383internal void InitDataSource()384{385DataBand dataBand = GroupDataBand;386GroupHeaderBand group = this;387int index = 0;388// insert group sort to the databand389while (group != null)390{391if (group.SortOrder != SortOrder.None)392{393dataBand.Sort.Insert(index, new Sort(group.Condition, group.SortOrder == SortOrder.Descending));394index++;395}396group = group.NestedGroup;397}398
399dataBand.InitDataSource();400}401
402internal void FinalizeDataSource()403{404DataBand dataBand = GroupDataBand;405GroupHeaderBand group = this;406// remove group sort from the databand407while (group != null)408{409if (group.SortOrder != SortOrder.None)410dataBand.Sort.RemoveAt(0);411group = group.NestedGroup;412}413}414
415internal void ResetGroupValue()416{417if (!string.IsNullOrEmpty(Condition))418{419groupValue = Report.Calc(Condition);420}421else422{423throw new GroupHeaderHasNoGroupCondition(Name);424}425}426
427internal bool GroupValueChanged()428{429object value = null;430if (!string.IsNullOrEmpty(Condition))431{432value = Report.Calc(Condition);433}434else435{436throw new GroupHeaderHasNoGroupCondition(Name);437}438if (groupValue == null)439{440if (value == null)441return false;442return true;443}444return !groupValue.Equals(value);445}446#endregion447
448/// <summary>449/// Initializes a new instance of the <see cref="GroupHeaderBand"/> class with default settings.450/// </summary>451public GroupHeaderBand()452{453condition = "";454sortOrder = SortOrder.Ascending;455}456}457}