C#에서 PrintDocument를 사용하여 간단한 보고서를 만드는 방법
페이지 정보
작성자 GrapeCity
본문
관련링크
보고는 비즈니스 분야에서 일반적인 작업입니다. 복잡한 보고서를 만들 수 있는 특수 FlexReport 컨트롤이 있지만 특수 도구를 사용하는 것은 너무 어렵거나 유연하지 않을 수 있습니다. 이러한 경우를 위해 더욱 간단하고 가벼운 도구인 C1PrintDocument가 있습니다.
수년 동안 C1PrintDocument 컴포넌트는 C1Report 어셈블리에 포함되었지만 사용이 중단되었습니다. 2021 v2 릴리스에서는 C1PrintDocument를 어셈블리로 분리하는 동시에 .NET 5에 이식했습니다.
C1PrintDocument 및 관련 미리 보기 컨트롤은 (WinForms 버전)에 새로 추가되었습니다. 이제 WPF 버전은 .NET 4.5.2에서만 사용할 수 있으며, 에서 볼 수 있습니다.
C1PrintDocument 소개
는 다양한 레이아웃(인라인, 스택), 주변 및 계층 스타일, 무한대로 중첩된 표, 목차, 페이지 매김 정밀 컨트롤(단락의 첫 줄이나 마지막 줄 분리 방지, 페이지 크기/헤더/푸터 등) 등에 대한 지원과 함께 다양한 기능을 갖춘 광범위한 DOM(문서 객체 모델)을 제공합니다. 무엇보다 데이터 바인딩 레이어도 있습니다.
이러한 내용에 대해 잘 알고 있으면 코드를 사용하여 복잡하고 유연한 문서를 비교적 쉽게 만든 다음 PDF(Portable Document Format), RTF(서식 있는 텍스트 파일), MS Excel 및 기타 형식으로 보거나 인쇄하거나 저장하거나 내보낼 수 있습니다.
페이지 매김 및 여러 레이아웃 옵션을 사용하여 임의 텍스트를 인쇄해야 하는 경우 다음과 같은 간단한 코드를 사용하여 시작할 수 있습니다.
C1PrintDocument을 사용하여 "Hello World" 출력하기
// create C1PrintDocument instance var doc = new C1.C1Preview.C1PrintDocument(); // insert content doc.Body.Children.Add(new C1.C1Preview.RenderText(doc, "Hello World!")); //force document generation doc.Generate(); // preview what you got with RibbonPreviewDialog var preview = new C1.Win.RibbonPreview.C1RibbonPreviewDialog(); preview.Document = doc; preview.ShowDialog();
미리 보기 대화 상자에서 페이지 설정을 사용하여 콘텐츠 공간이 조정되는 방식을 보고 코드 작업 없이 페이지를 매길 수 있습니다.
보다 복잡한 보고서와 같은 응용 프로그램이 필요한 경우 요소의 레이아웃을 정의하고 데이터 바인딩을 사용하여 데이터에 따라 요소를 생성해야 합니다. 작업 방법을 보여 주기 위해 압축 파일로 다운로드할 수 있는 을 제공해 드립니다. 이제 몇 가지 개별 샘플과 기술에 대해 말씀드리겠습니다.
간단한 보고서 만들기
가장 단순한 "고객 레이블" 샘플에는 왼쪽에서 오른쪽 방향의 레이블을 한 페이지에 들어갈 수 있는 한 최대한 많이 표시합니다.
C1PrintDocument를 작성하려면 클래스에서 파생된 요소를 사용하고 C1PrintDocument.Body에 추가해야 합니다.
WinForms 응용 프로그램에서 control.Controls 컬렉션에 컨트롤을 추가한 것과 동일한 방식으로 컬렉션에 추가합니다. 요소를 중첩할 수 있고 부모 객체 바인딩을 데이터 소스로 사용할 수 있습니다.
는 자식 객체를 위한 컨테이너인 렌더 객체입니다. 기본적으로 새 RenderArea가 생성되면 그 너비는 부모 영역의 너비와 같습니다.
RenderArea의 경우 너비 또는 높이를 "Unit.Auto"로 지정하면 자식의 크기가 적절한 크기를 결정합니다.
컨테이너(부모 객체 또는 문서 본문) 내에서 기본적으로 렌더 객체는 누적 규칙에 따라 배치되고 컨테이너(최상위 객체 또는 문서 바디)의 속성 값으로 결정됩니다.
이 값은 다음 열거 멤버 중 하나일 수 있습니다.
BlockTopToBottom: 객체는 컨테이너 내에서 다른 객체 아래에 배치됩니다. 현재 페이지의 아래쪽 가장자리에 도달하면 새 페이지가 추가됩니다. 이는 기본값입니다.
BlockLeftToRight: 객체가 왼쪽에서 오른쪽으로 다른 객체 옆에 배치됩니다. 현재 페이지의 오른쪽 가장자리에 도달하면 새 "가로" 페이지가 추가됩니다. 가로 페이지는 이전 페이지를 논리적으로 오른쪽으로 확장합니다.
InlineLeftToRight: 객체가 왼쪽에서 오른쪽으로 다른 객체 옆에 인라인 방식으로 배치됩니다. 현재 페이지의 오른쪽 가장자리에 도달하면 시퀀스가 다음 줄로 줄바꿈됩니다. 현재 페이지의 맨 아래에 도달하면 새 페이지가 추가됩니다.
"고객 레이블" 문서의 레이아웃은 다음과 같은 여러 가지 핵심 요소로 구성됩니다.
외부 RenderArea 객체 "raContainer"는 모든 레이블에 대한 컨테이너로 작동합니다.
RenderArea 객체 "raItem"은 단일 레이블을 나타냅니다.
RenderText 객체 "rt"는 레이블 콘텐츠를 나타냅니다.
다음과 같이 나타납니다.
코드 중 일부분을 좀 더 자세히 보여 드리겠습니다.
고객 레이블 코드
// create outer render area RenderArea raContainer = new RenderArea(); // define left-to-right flow for child elements raContainer.Stacking = StackingRulesEnum.InlineLeftToRight; _printDocument.Body.Children.Add(raContainer); // define data schema DataSource ds = CreateDemoDataSource(); DataSet dsCustomers = new DataSet(ds, "SELECT CompanyName, Address, City, PostalCode, Country FROM Customers ORDER BY CompanyName"); // add data set to the document _printDocument.DataSchema.DataSets.Add(dsCustomers); // create render area representing single label RenderArea raItem = new RenderArea(); // set right and bottom borders as light gray dotted lines 0.1 point wide raItem.Style.Borders.Right = new LineDef("0.1pt", Color.LightGray, System.Drawing.Drawing2D.DashStyle.Dot); raItem.Style.Borders.Bottom = new LineDef("0.1pt", Color.LightGray, System.Drawing.Drawing2D.DashStyle.Dot); // set size in millimeters raItem.Width = "40mm"; raItem.Height = "20mm"; // do not split the label into different pages raItem.SplitVertBehavior = SplitBehaviorEnum.Never; // set the data source raItem.DataBinding.DataSource = dsCustomers; // add label as a child to outer container raContainer.Children.Add(raItem); // define text which should be printed inside label RenderText rt = new RenderText(); rt.Text = "[Fields!CompanyName.Value]\r\n[Fields!Address.Value]\r\n[Fields!City.Value] [Fields!PostalCode.Value]\r\n[Fields!Country.Value]"; // Add the text as a child of label raItem.Children.Add(rt); // generate document _printDocument.Generate();
그룹 사용
C1PrintDocument를 사용하면 식을 사용하여 데이터를 그룹화할 수 있습니다. "제품의 사전순 목록" 샘플은 제품 이름의 첫 번째 문자로 제품을 그룹화하여 아래와 같이 보기 좋게 정렬된 제품 목록을 보여 줍니다.
이 샘플에는 데이터가 표 형식으로 배치되어 있습니다. 이 표는 클래스를 사용하여 만들었습니다. 표의 크기에는 제한이 없고, 콘텐츠가 지정된 가장 높은 행 및 열 번호에 해당하는 셀에 따라 렌더링 시 표 크기가 결정됩니다.
행과 열의 인덱스는 0부터 시작합니다. 기본적으로 표의 크기는 부모 요소의 클라이언트 영역 너비와 동일합니다. 행 높이는 행에서 가장 큰 콘텐츠 높이에 맞춰 자동으로 설정됩니다.
제품의 사전순 목록 코드
// Define data schema DataSource ds = CreateDemoDataSource(); // Create DataSet containing data selected from database // "FirstLetter" field is the first letter of product name DataSet dsProducts = new DataSet(ds, "SELECT Left(p.ProductName, 1) AS FirstLetter, p.ProductName, p.QuantityPerUnit, p.UnitsInStock, c.CategoryName " + "FROM Categories c, Products p " + "WHERE c.CategoryID = p.CategoryID " + "ORDER BY p.ProductName"); // Add data source and data set to the document: // this will preserve the data binding if the document is saved as c1d/c1dx _printDocument.DataSchema.DataSources.Add(ds); _printDocument.DataSchema.DataSets.Add(dsProducts); // RenderTable class is used to create a table RenderTable rt = new RenderTable(); // TableVectorGroup collection is used to group the data by "FirstLetter" field. // The RowGroups property accepts two integers. // The first value is the index of the first row included in the group (0). // The second value is the count of rows in the group (3). TableVectorGroup tvg = rt.RowGroups[0, 3]; // Using the DataBinding property in the TableVectorGroup, which is the base class for table row and column groups, a RenderTable can be data bound. tvg.DataBinding.DataSource = dsProducts; // Group by “FirstLetter” query result field tvg.DataBinding.Grouping.Expressions.Add("Fields!FirstLetter.Value"); // Set header row rt.Cells[0, 0].Text = "[Fields!FirstLetter.Value]"; // Merge cells from [0, 1] to [0, 4] rt.Cells[0, 1].SpanCols = 4; // Set sub-header row rt.Cells[1, 1].Text = "Product Name:"; rt.Cells[1, 2].Text = "Category Name:"; rt.Cells[1, 3].Text = "Quantity Per Unit:"; rt.Cells[1, 4].Text = "Units In Stock:"; // Set data row // "[Fields!ProductName.Value]" means to take the value of the "ProductName" field from the query result rt.Cells[2, 1].Text = "[Fields!ProductName.Value]"; rt.Cells[2, 2].Text = "[Fields!CategoryName.Value]"; rt.Cells[2, 3].Text = "[Fields!QuantityPerUnit.Value]"; rt.Cells[2, 4].Text = "[Fields!UnitsInStock.Value]"; // Create a nested (second) group of rows tvg = rt.RowGroups[2, 1]; tvg.DataBinding.DataSource = dsProducts; // Add table to the document _printDocument.Body.Children.Add(rt); // Generate document _printDocument.Generate();
참고: 그룹의 범위는 겹치면 안 됩니다.
표현식 사용하기
표현식(또는 스크립트)은 C1PrintDocument에서 콘텐츠를 추출, 계산, 표시, 그룹화, 정렬, 필터링, 매개 변수화하고, 콘텐츠의 서식을 지정하며, 보고서의 기능을 확장하는 데 사용됩니다. 스크립트에 대한 자세한 내용은 에서 확인할 수 있습니다.
기본적으로 Visual Basic이 표현식 언어로 사용됩니다. C#을 사용하려면 속성을 변경하세요.
"Employees" 샘플에서는 스크립트를 사용하여 생성된 문서에 사진을 삽입합니다.
이 샘플에서는 속성을 사용하여 데이터 바인딩 확인으로 인해 현재 의 새 인스턴스가 생성될 때마다 실행되는 스크립트를 설정합니다.
Employees 코드
// define data set DataSet dsEmployers = new DataSet(ds, "SELECT EmployeeID, LastName, FirstName, Title, TitleOfCourtesy, BirthDate, HireDate, Address, City, Region, PostalCode, Country, HomePhone, Extension, Notes, ReportsTo, Photo " + "FROM Employees " + "ORDER BY Country, City, FirstName, LastName"); // add data source and data set to the document: this will preserve the data binding if the document is saved as c1d/c1dx _printDocument.DataSchema.DataSources.Add(ds); _printDocument.DataSchema.DataSets.Add(dsEmployers); // create table RenderTable rt = new RenderTable(); // set header row rt.Cells[0, 0].Text = "Country"; rt.Cells[0, 1].Text = "City"; rt.Cells[0, 2].Text = "Address"; rt.Cells[0, 3].Text = "Home Phone"; // set country row rt.Cells[1, 0].Text = "[Fields!Country.Value]"; // set city row rt.Cells[2, 1].Text = "[Fields!City.Value]"; // set data rows rt.Cells[3, 0].Text = "[Fields!FirstName.Value] [Fields!LastName.Value]"; rt.Cells[3, 0].SpanCols = 2; rt.Cells[3, 2].Text = "[Fields!Address.Value]"; rt.Cells[3, 3].Text = "[Fields!HomePhone.Value]"; RenderImage ri = new RenderImage(_printDocument); // show all exceptions and warnings for script debug _printDocument.ThrowExceptionOnError = true; _printDocument.AddWarningsWhenErrorInScript = true; // using the VB script to extract an image from query resault ri.FormatDataBindingInstanceScript = @" ' get ri object Dim ri as RenderImage = DirectCast(RenderObject, RenderImage) ' get DB BLOB object as byte array Dim picData as Byte() = DirectCast(RenderObject.Original.DataBinding.Parent.Fields!Photo.Value, Byte()) Const bmData As Integer = 78 Dim ms as IO.MemoryStream = New IO.MemoryStream(picData, bmData, picData.Length - bmData) ' create image from stream ri.Image = Image.FromStream(ms) "; // set image parameters ri.Width = "30mm"; ri.Height = "30mm"; ri.Style.ImageAlign.AlignHorz = ImageAlignHorzEnum.Center; ri.Style.ImageAlign.AlignVert = ImageAlignVertEnum.Center; rt.Cells[4, 0].RenderObject = ri; rt.Cells[4, 0].SpanCols = 2; rt.Cells[4, 0].SpanRows = 2; rt.Cells[4, 2].Text = "[Fields!Title.Value]"; rt.Cells[4, 2].Style.Parents = dataStyle; rt.Cells[4, 3].Text = "[FormatDateTime(Fields!BirthDate.Value, DateFormat.ShortDate)] [FormatDateTime(Fields!HireDate.Value, DateFormat.ShortDate)]"; rt.Cells[4, 3].Style.Parents = dataStyle; // add area for notes RenderArea raNotes = new RenderArea(); var rtNoteTitle = new RenderText(); rtNoteTitle.Text = "[Fields!FirstName.Value]`s notes:"; // add note text var rtNote = new RenderText(); rtNote.Text = "[Fields!Notes.Value]"; // do not split the area into different pages raNotes.SplitVertBehavior = SplitBehaviorEnum.Never; raNotes.Children.Add(rtNoteTitle); raNotes.Children.Add(rtNote); rt.Cells[5, 2].RenderObject = raNotes; // create group by city TableVectorGroup tvg = rt.RowGroups[2, 6]; tvg.DataBinding.DataSource = dsEmployers; tvg.DataBinding.Grouping.Expressions.Add("Fields!City.Value"); // create group by country tvg = rt.RowGroups[0, 8]; tvg.DataBinding.DataSource = dsEmployers; tvg.DataBinding.Grouping.Expressions.Add("Fields!Country.Value"); // add data rows tvg = rt.RowGroups[3, 5]; tvg.DataBinding.DataSource = dsEmployers; tvg.SplitBehavior = SplitBehaviorEnum.Never; // add table to the document _printDocument.Body.Children.Add(rt); // define a cell group style for the rectangular area of table cells, you can set the style rt.UserCellGroups.Add(new UserCellGroup(new Rectangle(0, 3, 4, 3))); rt.UserCellGroups[0].Style.Borders.All = new LineDef("0.5pt", Color.Black); // generate document _printDocument.Generate();
C1PrintDocument 계층 구조의 여러 객체에는 데이터에 따라 즉시 모양 변화를 허용하는 스크립트를 수락하는 속성이 있습니다. 예를 들어, 식에서는 스타일을 사용하여 $1000가 넘는 주문을 파란색으로 강조 표시할 수 있습니다.
조건별 텍스트 색
rt.Cells[3, 4].Style.TextColorExpr = "iif(Fields!UnitPrice.Value * Fields!Quantity.Value >= 1000, Colors.Blue, Colors.Black)";
스타일 사용
C1PrintDocument 속성은 테두리, 글꼴, 텍스트의 선 간격 등 시각적 컴포넌트의 기본 모양을 설정할 수 있는 문서의 루트 스타일입니다.
C1PrintDocument PageLayout. 속성을 사용하면 인쇄를 위한 페이지 옵션을 설정하여 용지 크기, 페이지 방향 등을 선택할 수 있습니다.
문서 페이지의 경우 클래스의 속성을 사용하여 설정을 조정할 수 있습니다. 이 속성은 할당할 수 없습니다. 현재 객체의 스타일에 대해 다른 스타일을 기본으로 지정하려면 Parent를 다른 스타일로 설정하세요.
스타일 설정
// set default style for document _printDocument.Style.FontName = "Verdana"; _printDocument.Style.FontSize = 10; // set margin to pages in millimeters _printDocument.PageLayout.PageSettings.LeftMargin = "12mm"; _printDocument.PageLayout.PageSettings.RightMargin = "12mm"; _printDocument.PageLayout.PageSettings.TopMargin = "12mm"; _printDocument.PageLayout.PageSettings.BottomMargin = "12mm"; // set group header style // for large documents it is better to create a named style for reuse C1.C1Preview.Style headerStyle = _printDocument.Style.Children.Add(); headerStyle.FontSize = 9; headerStyle.FontBold = true; headerStyle.GridLines.Bottom = new LineDef("1pt", Color.Black); // set country header style C1.C1Preview.Style countryStyle = _printDocument.Style.Children.Add(); countryStyle.FontSize = 11; countryStyle.FontBold = true; // set city header style C1.C1Preview.Style cityStyle = _printDocument.Style.Children.Add(); cityStyle.FontSize = 10; cityStyle.FontUnderline = true; // set document caption var rtCaption = new RenderText(); rtCaption.Text = "Employees"; // set style parameters directly is fine for small documents or styles used just once rtCaption.Style.FontName = "Tahoma"; rtCaption.Style.FontSize = 16; rtCaption.Style.Padding.All = "2mm"; rtCaption.Style.BackColor = Color.LightGray; _printDocument.Body.Children.Add(rtCaption); // create table RenderTable rt = new RenderTable(); // set top, left, bottom, right padding of content within the cell to 1 millimeter rt.CellStyle.Padding.All = "1mm"; // set header row rt.Cells[0, 0].Text = "Country"; rt.Cells[0, 0].Style.Spacing.Top = "2mm"; rt.Cells[0, 0].Style.Parents = headerStyle; rt.Cells[0, 1].Text = "City"; rt.Cells[0, 1].Style.Parents = headerStyle; rt.Cells[0, 2].Text = "Address"; rt.Cells[0, 2].Style.Parents = headerStyle; rt.Cells[0, 3].Text = "Home Phone"; rt.Cells[0, 3].Style.Parents = headerStyle; // set country row rt.Cells[1, 0].Text = "[Fields!Country.Value]"; rt.Cells[1, 0].Style.Parents = countryStyle; // set city row rt.Cells[2, 1].Text = "[Fields!City.Value]"; rt.Cells[2, 1].Style.Parents = cityStyle; // define style for the rectangular area of table cells from cell where row = 0, column = 3, the 4 cells width and the 3 cells height rt.UserCellGroups.Add(new UserCellGroup(new Rectangle(0, 3, 4, 3))); // add to cell the black border of 0.5 point width rt.UserCellGroups[0].Style.Borders.All = new LineDef("0.5pt", Color.Black);
집계 사용
평균 보고서의 경우 단순히 데이터를 그룹화하는 것으로는 충분치 않습니다. 사람들은 일반적으로 보고서 맨 아래에서 집계된 값을 보고 싶어 합니다. "국가별 직원 매출" 샘플에서 집계를 추가하는 방법을 살펴보겠습니다.
국가별 직원 매출 코드
// set dates var date1 = new DateTime(2015, 9, 7, 0, 0, 0); var date2 = new DateTime(2016, 5, 5, 0, 0, 0); var dsSales = new DataSet(dataSource, string.Format( "SELECT o.ShipCountry, e.EmployeeID, e.FirstName, e.LastName, o.ShippedDate, o.Freight " + "FROM Employees e, Orders o " + "WHERE e.EmployeeID = o.EmployeeID AND o.ShippedDate IS NOT NULL AND o.ShippedDate BETWEEN #{0} 00:00:00# AND #{1} 00:00:00# " + "ORDER BY o.ShipCountry, e.FirstName, e.LastName, o.ShippedDate", date1.ToString(@"MM\/dd\/yyyy"), date2.ToString(@"MM\/dd\/yyyy"))); // add data source and data set to the document: this will preserve the data binding if the document is saved as c1d/c1dx _printDocument.DataSchema.DataSources.Add(dataSource); _printDocument.DataSchema.DataSets.Add(dsSales); // add caption var raCaption = new RenderArea(); var header1 = new RenderText(); header1.Text = "Employee sales by country"; var header2 = new RenderText(); header2.Text = string.Format("Between {0} and {1}", date1.ToShortDateString(), date2.ToShortDateString()); raCaption.Children.Add(header1); raCaption.Children.Add(header2); _printDocument.Body.Children.Add(raCaption); // create table var rt = new RenderTable(); // header: country rt.Cells[0, 0].Text = "[Fields!ShipCountry.Value]"; rt.Cells[0, 2].Text = "$[Aggregates!SumByCountry.Value]"; // data rt.Cells[1, 0].Text = "[Fields!FirstName.Value] [Fields!LastName.Value]"; rt.Cells[1, 1].Text = "[Math.Round(Aggregates!SumByEmployee.Value / Aggregates!SumByCountry.Value * 100, 1)]%"; rt.Cells[1, 2].Text = "$[Aggregates!SumByEmployee.Value]"; // create a group by ship country to be repeated for each group TableVectorGroup tvg = rt.RowGroups[0, 2]; tvg.DataBinding.DataSource = dsSales; // data is grouped by the "ShipCountry" field tvg.DataBinding.Grouping.Expressions.Add("Fields!ShipCountry.Value"); // Create an aggregate that will calculate the sum of "Freight" fields within each grouping by the "ShipCountry" field _printDocument.DataSchema.Aggregates.Add(new Aggregate("SumByCountry", "Fields!Freight.Value", tvg.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum)); tvg = rt.RowGroups[1, 1]; tvg.DataBinding.DataSource = dsSales; tvg.DataBinding.Grouping.Expressions.Add("Fields!EmployeeID.Value"); // add total sum by employee aggregate value: data grouped by the "EmployeeID" field, the sum of the "Freight" field values is calculated _printDocument.DataSchema.Aggregates.Add(new Aggregate("SumByEmployee", "Fields!Freight.Value", tvg.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum)); // add data rows tvg = rt.RowGroups[1, 1]; tvg.DataBinding.DataSource = dsSales; // add table to the document _printDocument.Body.Children.Add(rt); // generate document _printDocument.Generate();
위 코드에서 집계는 메서드 호출 new Aggregate("SumByCountry", "Fields!Freight.Value", tvg.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum)으로 생성됩니다. 매개 변수는 다음과 같습니다.
"SumByCountry"는 집계 이름입니다.
"Fields!Freight.Value"는 합계를 계산하기 위한 식입니다.
"tvg.DataBinding"은 집계를 위한 데이터 소스입니다.
"RunningEnum.Group"은 집계에 그룹 범위가 있음을 의미합니다.
"AggregateFuncEnum.Sum"은 집계가 범위 내에서 식의 값 합계를 반환함을 의미합니다.
C1PrintDocument.DataSchema.Aggregates.Add 메서드는 Aggregates 컬렉션에 Aggregate 객체를 추가합니다. 그러면 이름이 "SumByCountry"인 집계를 문서의 모든 위치에서 사용할 수 있습니다(예: rt.Cells[0, 2].Text = "$[Aggregates!SumByCountry.Value]").
document.Aggregates 컬렉션에 집계를 반드시 추가할 필요는 없습니다. 에 표시된 대로 는 모든 식에서 직접 사용할 수 있습니다.
차트 그리기
대부분 사람들은 데이터를 시각적으로 표현한 것을 보고 싶어 합니다. "카테고리 별 매출" 샘플에서는 컨트롤을 사용하여 차트를 생성한 다음 문서에 이미지를 삽입합니다.
다음은 이 샘플의 미리 보기입니다.
C1PrintDocument 스크립트에서 임의의 어셈블리를 사용하려면 C1PrintDocument.ScriptingOptions.ExternalAssemblies 컬렉션에 해당 어셈블리를 추가해야 합니다. FlexChart를 사용하려면 FlexChart와 해당 종속 항목에 참조를 추가해야 합니다.
카테고리 별 매출 코드
// adding assemblies referenced in script _printDocument.ScriptingOptions.ExternalAssemblies.Add(typeof(Form).Assembly.ManifestModule.Name); _printDocument.ScriptingOptions.ExternalAssemblies.Add(typeof(C1.Win.Chart.FlexChart).Assembly.ManifestModule.Name); _printDocument.ScriptingOptions.ExternalAssemblies.Add("System.Data.dll"); _printDocument.ScriptingOptions.ExternalAssemblies.Add("System.Xml.dll"); // create DataTable and assign it to document tag as data source for charts // the "dataTable" tag will be used to pass the DataTable value to the RenderImage object Tag newTag = new Tag("dataTable", GetDataSource(), typeof(System.Data.DataTable)); _printDocument.Tags.Add(newTag); // define data schema var dataSource = CreateDemoDataSource(); var dsCategories = new DataSet(dataSource, "SELECT c.CategoryName, p.ProductName, p.UnitPrice, p.UnitsInStock " + "FROM Products p, Categories c " + "WHERE p.CategoryID = c.CategoryID " + "ORDER BY c.CategoryName, p.ProductName"); // add data source and data set to the document: this will preserve the data binding if the document is saved as c1d/c1dx _printDocument.DataSchema.DataSources.Add(dataSource); _printDocument.DataSchema.DataSets.Add(dsCategories); var rt = new RenderTable(); // set header 1 rt.Cells[1, 0].Text = "[Fields!CategoryName.Value]"; // set header 2 rt.Cells[2, 0].Text = "Product:"; rt.Cells[2, 1].Text = "Sales:"; // set data row rt.Cells[3, 0].Text = "[Fields!ProductName.Value]"; rt.Cells[3, 1].Text = "[string.Format(\"{0:C}\",Fields!UnitPrice.Value * Fields!UnitsInStock.Value)]"; // create group by category name TableVectorGroup tvg = rt.RowGroups[0, 4]; tvg.DataBinding.DataSource = dsCategories; tvg.DataBinding.Grouping.Expressions.Add("Fields!CategoryName.Value"); // add data rows tvg = rt.RowGroups[3, 1]; tvg.DataBinding.DataSource = dsCategories; var raLeft = new RenderArea(); raLeft.Children.Add(rt); RenderArea raContainer = new RenderArea(); // arrange areas side-by-side raContainer.Stacking = StackingRulesEnum.InlineLeftToRight; // try to keep single category on a single page raContainer.SplitVertBehavior = SplitBehaviorEnum.SplitIfLarge; // set data bindings raContainer.DataBinding.DataSource = dsCategories; raContainer.DataBinding.Grouping.Expressions.Add("Fields!CategoryName.Value"); RenderImage ri = new RenderImage(_printDocument); // show all exceptions and warnings for script debug _printDocument.ThrowExceptionOnError = true; _printDocument.AddWarningsWhenErrorInScript = true; ri.FormatDataBindingInstanceScript = @"! see VB script below !"; RenderArea raRight = new RenderArea(); raRight.Children.Add(ri); raContainer.Children.Add(raLeft); raContainer.Children.Add(raRight); _printDocument.Body.Children.Add(raContainer); // generate document _printDocument.Generate();
Visual Basic 스크립트(위 코드에서 FormatDataBindingInstanceScript에 사용됨)는 차트 객체를 생성하여 해당 객체에 데이터 소스를 할당한 다음 차트를 이미지로 변환합니다.
차트를 만드는 Visual Basic 스크립트
' create chart Dim chart as C1.Win.Chart.FlexChart = New C1.Win.Chart.FlexChart() ' set chart parameters chart.BindingX = ""ProductName"" ' assign the name of the property that contains X values for the series chart.Binding = ""UnitPrice"" ' assign the name of the property for the DataSource property to use in axis labels chart.BindingContext = New System.Windows.Forms.BindingContext() chart.AxisX.Style.Font = new System.Drawing.Font(""Tahoma"", 7, System.Drawing.FontStyle.Regular) chart.ChartType = C1.Chart.ChartType.Column ' show vertical bars chart.BackColor = Color.White chart.AxisX.OverlappingLabels = C1.Chart.OverlappingLabels.Auto ' hide overlapping labels chart.AxisX.LabelAngle = 90 ' the rotation angle of the axis labels Dim series = new C1.Win.Chart.Series() chart.Series.Add(series) ' set chart size Dim size as Size = New Size(340, 270) ' assign data source Dim documentTag = DirectCast(Document.Tags, TagCollection) Dim dt = DirectCast(documentTag!dataTable.Value, System.Data.DataTable) ' get the "dataTable" tag Dim dv as System.Data.DataView = New System.Data.DataView(dt) Dim filter as String = ""CategoryName = "" & RenderObject.Original.Parent.DataBinding.Parent.Fields!CategoryName.Value & ""'"" dv.RowFilter = filter chart.DataSource = dv ' create the chart image Dim ms as IO.MemoryStream = New IO.MemoryStream() chart.SaveImage(ms, C1.Win.Chart.ImageFormat.Png, size.Width, size.Height) ' assign the image to RenderImage object Dim ri as RenderImage = DirectCast(RenderObject, RenderImage) ri.Image = Image.FromStream(ms)
마찬가지로, 참조에 사용자 정의 어셈블리를 추가하고 문서 스크립트에서 클래스를 사용할 수 있습니다.
C1PrintDocument 구조는 계층적이고 비교적 간단합니다. 데이터는 바인딩을 사용하여 설정되고 데이터의 모양을 정의하는 그룹으로 표시됩니다.
RenderObject에서 상속되는 각 요소는 기능을 확장하는 스크립트 실행을 지원합니다. C1PrintDocument는 여러 레이아웃 옵션을 사용하여 간단한 보고서를 만들거나 바인딩되지 않은 텍스트를 인쇄하기 위한 뛰어난 도구입니다.
.NET 4.5.2 버전과 .NET 5, .NET 6 등의 버전에서 C1PrintDocument를 계속 지원할 것입니다.
문서에서 자세한 내용을 찾아볼 수 있습니다.
지금 바로 ComponentOne을 다운로드하여 직접 테스트해보세요!
댓글목록
등록된 댓글이 없습니다.