/// <summary> /// Creates a RenderParagraph containing a caption (label) and an expression /// referencing an aggregate with the specified name, delimited by a newline. /// The aggregate must be added to the document's DataSchema.Aggregates separately. /// </summary> /// <param name="caption">The caption text</param> /// <param name="aggregateName">The aggregate name.</param> /// <param name="captionStyle">Style for the caption text.</param> /// <param name="aggregateStyle">Style for the aggregate value.</param> /// <param name="currency">If true, value is formatted as currency.</param> /// <returns>The created RenderParagraph object.</returns> private RenderObject CreateAggregate1(string caption, string aggregateName, C1.C1Preview.Style captionStyle, C1.C1Preview.Style aggregateStyle, bool currency) { RenderParagraph result = new RenderParagraph(); ParagraphText pt = new ParagraphText(caption + "\r"); pt.Style.Parents = captionStyle; result.Content.Add(pt); if (currency) { pt = new ParagraphText("[string.Format(\"{0:C}\",Aggregates!" + aggregateName + ".Value)]"); } else { pt = new ParagraphText("[Aggregates!" + aggregateName + ".Value]"); } pt.Style.Parents = aggregateStyle; result.Content.Add(pt); return(result); }
/// <summary> /// Builds a document with a data bound table, with two levels of master-detail relations. /// </summary> private void btnBoundTable_Click(object sender, RoutedEventArgs e) { UpdateButtons(btnBoundTable); this.Cursor = Cursors.Wait; C1PrintDocument doc = new C1PrintDocument(); // Set up some styles: doc.Style.FontName = "Verdana"; doc.Style.FontSize = 10; C1.C1Preview.Style boldFontStyle = doc.Style.Children.Add(); boldFontStyle.FontName = "Verdana"; boldFontStyle.FontSize = 10; boldFontStyle.FontBold = true; C1.C1Preview.Style smallFontStyle = doc.Style.Children.Add(); smallFontStyle.FontName = "Verdana"; smallFontStyle.FontSize = 7; C1.C1Preview.Style detailCaptionStyle = doc.Style.Children.Add(); detailCaptionStyle.TextAlignHorz = AlignHorzEnum.Center; detailCaptionStyle.TextAlignVert = AlignVertEnum.Center; detailCaptionStyle.FontName = "Verdana"; detailCaptionStyle.FontSize = 8; detailCaptionStyle.FontUnderline = true; C1.C1Preview.Style detailStyle = doc.Style.Children.Add(); detailStyle.FontName = "Verdana"; detailStyle.FontSize = 11; C1.C1Preview.Style dateStyle = detailStyle.Children.Add(); dateStyle.TextAlignHorz = AlignHorzEnum.Center; C1.C1Preview.Style descriptionStyle = detailStyle.Children.Add(); descriptionStyle.TextAlignHorz = AlignHorzEnum.Left; C1.C1Preview.Style currencyStyle = detailStyle.Children.Add(); currencyStyle.TextAlignHorz = AlignHorzEnum.Right; C1.C1Preview.Style quantityStyle = detailStyle.Children.Add(); quantityStyle.TextAlignHorz = AlignHorzEnum.Right; // define data schema: // orders sorted by customer sorted by customer country: DataSource ds = CreateDemoDataSource(); DataSet dsCities = new DataSet(ds, "select o.*, c.Country, c.CompanyName, p.ProductName, od.* from orders o, customers c, products p, `order details` od " + "where o.CustomerID = c.CustomerID and o.OrderID = od.OrderID and od.ProductID = p.ProductID " + "order by c.Country, c.CompanyName, o.OrderDate"); // add data source and data set to the document - this will preserve the data binding // if the document is saved as c1d/c1dx: doc.DataSchema.DataSources.Add(ds); doc.DataSchema.DataSets.Add(dsCities); // document caption: RenderText txt = new RenderText(); txt.Text = "List of orders grouped by country and customer"; txt.Style.FontName = "Tahoma"; txt.Style.FontSize = 16; txt.Style.FontBold = true; doc.Body.Children.Add(txt); // main body of the document is a data bound table, with 3 nested data bound row groups: RenderTable rt = new RenderTable(); // the following two lines make table and table columns auto-sized: rt.Width = Unit.Auto; rt.ColumnSizingMode = TableSizingModeEnum.Auto; // spread out data a bit: rt.CellStyle.Padding.All = "0.5mm"; // turn lines on for structure clarity: rt.Style.GridLines.All = new LineDef("0.5pt", Colors.Silver); // top level master: country: rt.Cells[0, 0].Text = "Country:"; rt.Cells[0, 1].SpanCols = 2; rt.Cells[0, 1].Text = "[Fields!Country.Value]"; rt.Cells[0, 1].Style.Parents = boldFontStyle; // top level master: orders count for country: rt.Cells[0, 3].RenderObject = CreateAggregate1("Total orders:", "CountryOrderCount", smallFontStyle, boldFontStyle, false); // top level master: orders total for country: rt.Cells[0, 4].RenderObject = CreateAggregate1("Country total:", "CountryTotal", smallFontStyle, boldFontStyle, true); // country header back color: rt.Rows[0].Style.BackColor = Colors.LightGoldenrodYellow; // second level master: company: rt.Cells[1, 0].Text = "Company:"; rt.Cells[1, 1].Text = "[Fields!CompanyName.Value]"; rt.Cells[1, 1].Style.Parents = boldFontStyle; rt.Cells[1, 1].SpanCols = 2; // second level master: orders count for company: rt.Cells[1, 3].RenderObject = CreateAggregate1("Total orders:", "CompanyOrderCount", smallFontStyle, boldFontStyle, false); // second level master: orders total for company: rt.Cells[1, 4].RenderObject = CreateAggregate1("Company total:", "CompanyTotal", smallFontStyle, boldFontStyle, true); // company header back color: rt.Rows[1].Style.BackColor = Colors.Lavender; // detail: column captions: rt.Cells[2, 0].Text = "Date"; rt.Cells[2, 0].Style.Parents = detailCaptionStyle; rt.Cells[2, 1].Text = "Product"; rt.Cells[2, 1].Style.Parents = detailCaptionStyle; rt.Cells[2, 2].Text = "Unit Price"; rt.Cells[2, 2].Style.Parents = detailCaptionStyle; rt.Cells[2, 3].Text = "Quantity"; rt.Cells[2, 3].Style.Parents = detailCaptionStyle; rt.Cells[2, 4].Text = "Total"; rt.Cells[2, 4].Style.Parents = detailCaptionStyle; // detail: data: // 1) detail: order date: rt.Cells[3, 0].Text = "[FormatDateTime(Fields!OrderDate.Value, DateFormat.ShortDate)]"; rt.Cells[3, 0].Style.Parents = dateStyle; // 2) detail: product name: rt.Cells[3, 1].Text = "[Fields!ProductName.Value]"; rt.Cells[3, 1].Style.Parents = descriptionStyle; // 3) detail: unit price: rt.Cells[3, 2].Text = "[string.Format(\"{0:C}\",Fields!UnitPrice.Value)]"; rt.Cells[3, 2].Style.Parents = currencyStyle; // 4) detail: quantity: rt.Cells[3, 3].Text = "[Fields!Quantity.Value]"; rt.Cells[3, 3].Style.Parents = quantityStyle; // 5) detail: order total: rt.Cells[3, 4].Text = "[string.Format(\"{0:C}\",Fields!UnitPrice.Value * Fields!Quantity.Value)]"; rt.Cells[3, 4].Style.Parents = currencyStyle; // New in 2009 v3 release of C1Report - style expressions. // Use it to highlight orders worth $1000 or more: rt.Cells[3, 4].Style.TextColorExpr = "iif(Fields!UnitPrice.Value * Fields!Quantity.Value >= 1000, Colors.Blue, Colors.Black)"; // top-level master footer: country total (duplicated in cell (0,4)): rt.Cells[5, 0].SpanCols = 3; rt.Cells[5, 0].Text = "Total of all orders for [Fields!Country.Value]:"; rt.Cells[5, 0].Style.TextAlignHorz = AlignHorzEnum.Right; rt.Cells[5, 3].SpanCols = 2; rt.Cells[5, 3].Style.Parents = currencyStyle; rt.Cells[5, 3].Text = "[string.Format(\"{0:C}\", Aggregates!CountryTotal.Value)]"; // Rows 6-8 create a visual break in the table after each country. // The 2 extra rows (6 & 8) are needed to make sure no extra grid lines // appear if this break is immediately followed by a page break. rt.Cells[6, 0].SpanCols = 5; rt.Cells[6, 0].RenderObject = new RenderEmpty("1pt"); rt.Cells[6, 0].Style.Borders.Left = rt.Cells[6, 0].Style.Borders.Right = LineDef.Empty; rt.Cells[6, 0].Style.Borders.Bottom = LineDef.Empty; rt.RowGroups[6, 1].MinVectorsBefore = 1; // rt.Cells[7, 0].SpanCols = 5; rt.Cells[7, 0].RenderObject = new RenderEmpty("3mm"); rt.Cells[7, 0].Style.Borders.All = LineDef.Empty; // rt.Cells[8, 0].SpanCols = 5; rt.Cells[8, 0].RenderObject = new RenderEmpty("1pt"); rt.Cells[8, 0].Style.Borders.Left = rt.Cells[8, 0].Style.Borders.Right = LineDef.Empty; rt.Cells[8, 0].Style.Borders.Top = LineDef.Empty; rt.RowGroups[8, 1].MinVectorsAfter = 1; // grand total for all countries: rt.Cells[9, 0].SpanCols = 2; rt.Cells[9, 0].Text = "Grand Total:"; rt.Cells[9, 0].Style.TextAlignHorz = AlignHorzEnum.Right; rt.Cells[9, 2].SpanCols = 3; rt.Cells[9, 2].Text = "[string.Format(\"{0:C}\", Aggregates!GrandTotal.Value)]"; rt.Cells[9, 2].Style.Parents = currencyStyle; // define databinding within table: // top level master row group - country - includes all defined rows (0-9): TableVectorGroup g = rt.RowGroups[0, 9]; g.DataBinding.DataSource = dsCities; // group by country: g.DataBinding.Grouping.Expressions.Add("Fields!Country.Value"); // add outline group header for each contry: g.DataBinding.OutlineText = "[Fields!Country.Value]"; g.SplitBehavior = SplitBehaviorEnum.SplitIfNeeded; // make sure country header is followed by company and at least one detail row: rt.RowGroups[0, 1].MinVectorsAfter = 3; // add country level aggregates (attached to top level master DataBinding): // (because there are several OrderID fields in the 'select' we must qualify it) doc.DataSchema.Aggregates.Add(new Aggregate("CountryOrderCount", "Fields(\"o.OrderID\").Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Count)); doc.DataSchema.Aggregates.Add(new Aggregate("CountryTotal", "Fields!UnitPrice.Value * Fields!Quantity.Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum)); // document level aggregate for the grand total: doc.DataSchema.Aggregates.Add(new Aggregate("GrandTotal", "Fields!UnitPrice.Value * Fields!Quantity.Value", g.DataBinding, RunningEnum.Document, AggregateFuncEnum.Sum)); // second level master row group - company - includes rows 1-4: g = rt.RowGroups[1, 4]; g.DataBinding.DataSource = dsCities; // group by company: g.DataBinding.Grouping.Expressions.Add("Fields!CompanyName.Value"); // add outline group header for each company: g.DataBinding.OutlineText = "[Fields!CompanyName.Value]"; g.SplitBehavior = SplitBehaviorEnum.SplitIfNeeded; // ensure company header is followed by at least one detail row: rt.RowGroups[1, 2].MinVectorsAfter = 1; rt.RowGroups[1, 2].SplitBehavior = SplitBehaviorEnum.SplitIfLarge; // add company level aggregates (attached to second level master DataBinding): doc.DataSchema.Aggregates.Add(new Aggregate("CompanyTotal", "Fields!UnitPrice.Value * Fields!Quantity.Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum)); // see note about OrderID above; but really, because we are just counting, any field would do here - e.g. CustomerID doc.DataSchema.Aggregates.Add(new Aggregate("CompanyOrderCount", "Fields(\"o.OrderID\").Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Count)); // finally, detail level data binding (just one row): g = rt.RowGroups[3, 1]; g.DataBinding.DataSource = dsCities; // add outline entry for each product name: g.DataBinding.OutlineText = "[Fields!ProductName.Value]"; // add table to the document: doc.Body.Children.Add(rt); // set up a progress window: ProgressWindow pw = new ProgressWindow(); pw.Owner = this; doc.Body.Children[0].UserData = pw; pw.Show(); doc.LongOperation += new LongOperationEventHandler(doc_LongOperation); // preview the document (this will cause the document to generate): c1DocumentViewer1.Document = doc.FixedDocumentSequence; // we're done; reset cursor: this.Cursor = null; }