using Autofac; using DevExpress.Data; using DevExpress.XtraEditors.Controls; using DevExpress.XtraPrinting; using DevExpress.XtraReports.UI; using GreenTree.Nachtragsmanagement.Core; using GreenTree.Nachtragsmanagement.Core.Authentication; using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Net.Mime; using System.Web; namespace GreenTree.Nachtragsmanagement.Web.Extensions { public class MVCxGridViewGeneratorHelper { public delegate void CustomizeColumnsCollectionEventHandler(object source, ColumnsCreationEventArgs e); public delegate void CustomizeColumnEventHandler(object source, ControlCustomizationEventArgs e); public delegate void CustomizeFormattingRulesEventHandler(object source, CustomFormattingRulesEventArgs e); public delegate void CustomizeColumnTotalSummaryEventHandler(object source, ColumnSummaryCreationEventArgs e); public delegate void CustomizeColumnGroupSummaryEventHandler(object source, ColumnSummaryCreationEventArgs e); public delegate void SummaryResetEventHandler(object source, CustomSummaryResetEventArgs e); public delegate void SummaryRowChangedEventHandler(object source, CustomSummaryRowChangedEventArgs e); public class MVCReportGeneratonHelper { const int initialGroupOffset = 0; const int subGroupOffset = 10; const int detaillOffset = 15; const int bandHeight = 20; const bool shouldRepeatGroupHeadersOnEveryPage = false; XtraReport report; Hashtable detailsInfo = new Hashtable(); Hashtable detailsWidth = new Hashtable(); public event CustomizeColumnsCollectionEventHandler CustomizeColumnsCollection; public event CustomizeColumnEventHandler CustomizeColumn; public event CustomizeFormattingRulesEventHandler CustomizeFormattingRules; public event CustomizeColumnTotalSummaryEventHandler CustomizeTotalColumnSummary; public event CustomizeColumnGroupSummaryEventHandler CustomizeGroupColumnSummary; public event SummaryResetEventHandler SummaryReset; public event SummaryRowChangedEventHandler SummaryRowChanged; public event SummaryGetResultHandler PageSummaryGetResult; public event SummaryGetResultHandler TotalSummaryGetResult; public XtraReport GenerateMVCReport(MVCxGridViewState gridViewState, object model, string title) { report = new XtraReport { Font = new Font("Calibri", 10f, FontStyle.Regular), Landscape = true, PaperKind = System.Drawing.Printing.PaperKind.A4 }; InitStyles(); InitReportTitle(title); InitDataSource(model); InitDetailsAndPageHeader(gridViewState); InitDetailReports(gridViewState); InitSortings(gridViewState); InitGroupHeaders(gridViewState); InitFilters(gridViewState); InitPageSummaries(gridViewState); InitTotalSummaries(gridViewState); InitPageFooter(); return report; } private void InitStyles() { report.StyleSheet.Add(new XRControlStyle { Name = "Title", Borders = DevExpress.XtraPrinting.BorderSide.None, Font = new Font(report.Font.FontFamily, 24f, FontStyle.Regular), ForeColor = Color.FromArgb(35, 133, 160) }); report.StyleSheet.Add(new XRControlStyle { Name = "OddRow", Borders = (DevExpress.XtraPrinting.BorderSide.Bottom | DevExpress.XtraPrinting.BorderSide.Left | DevExpress.XtraPrinting.BorderSide.Right), Padding = new PaddingInfo(30, 600) }); report.StyleSheet.Add(new XRControlStyle { Name = "EvenRow", BackColor = Color.LightGray, Borders = (DevExpress.XtraPrinting.BorderSide.Bottom | DevExpress.XtraPrinting.BorderSide.Left | DevExpress.XtraPrinting.BorderSide.Right), Padding = new PaddingInfo(30, 600) }); report.StyleSheet.Add(new XRControlStyle { Name = "HeaderRow", BackColor = Color.FromArgb(156, 183, 191), Borders = DevExpress.XtraPrinting.BorderSide.All, Padding = new PaddingInfo(30, 600), Font = new Font(report.Font, FontStyle.Bold) }); report.StyleSheet.Add(new XRControlStyle { Name = "GroupHeader", BackColor = Color.Beige, Borders = DevExpress.XtraPrinting.BorderSide.All, Padding = new PaddingInfo(30, 600), Font = new Font(report.Font, FontStyle.Bold) }); report.StyleSheet.Add(new XRControlStyle { Name = "SummaryRow", BackColor = Color.FromArgb(35, 133, 160), Borders = DevExpress.XtraPrinting.BorderSide.All, BorderColor = Color.FromArgb(35, 133, 160), Padding = new PaddingInfo(30, 600), ForeColor = Color.White, Font = new Font(report.Font, FontStyle.Bold) }); report.StyleSheet.Add(new XRControlStyle { Name = "DetailRowTable", Borders = DevExpress.XtraPrinting.BorderSide.All }); report.StyleSheet.Add(new XRControlStyle { Name = "DetailRow", BackColor = Color.FromArgb(209, 228, 255), Borders = DevExpress.XtraPrinting.BorderSide.None }); report.StyleSheet.Add(new XRControlStyle { Name = "DetailRowCell", Borders = DevExpress.XtraPrinting.BorderSide.All }); report.StyleSheet.Add(new XRControlStyle { Name = "DetailRowLabel", Padding = new PaddingInfo(30, 600), Borders = DevExpress.XtraPrinting.BorderSide.None }); report.StyleSheet.Add(new XRControlStyle { Name = "FooterRow", Font = new Font(report.Font, FontStyle.Italic) }); } private void InitReportTitle(string title) { report.Bands.Add(new ReportHeaderBand { HeightF = 32f }); report.Bands[BandKind.ReportHeader].Controls.Add(new XRLabel { Text = title, StyleName = "Title", WidthF = (report.PageWidth - (report.Margins.Left + report.Margins.Right)) }); } private void InitDataSource(object model) { report.DataSource = model; } private void InitDetailsAndPageHeader(MVCxGridViewState gridViewState) { var groupedColumns = gridViewState.GroupedColumns; var pagewidth = (report.PageWidth - (report.Margins.Left + report.Margins.Right)) - groupedColumns.Count * subGroupOffset; var columns = GetColumnsInfo(gridViewState, pagewidth); if (CustomizeColumnsCollection != null) CustomizeColumnsCollection(report, new ColumnsCreationEventArgs(pagewidth) { ColumnsInfo = columns }); report.Bands.Add(new DetailBand() { HeightF = bandHeight, KeepTogetherWithDetailReports = true }); report.Bands.Add(new PageHeaderBand() { HeightF = bandHeight }); var headerTable = new XRTable() { StyleName = "HeaderRow" }; var row = new XRTableRow(); var detailTable = new XRTable { OddStyleName = "OddRow", EvenStyleName = "EvenRow" }; var row2 = new XRTableRow(); for (var i = 0; i < columns.Count; i++) { if (columns[i].IsVisible) { var cell = new XRTableCell { Width = columns[i].ColumnWidth, Text = columns[i].GridViewColumn.Caption, Borders = DevExpress.XtraPrinting.BorderSide.All, TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft }; row.Cells.Add(cell); var cell2 = new XRTableCell { Width = columns[i].ColumnWidth }; var cc = new ControlCustomizationEventArgs { FieldName = columns[i].FieldName, IsModified = false, Owner = cell2, Header = cell }; if (CustomizeColumn != null) CustomizeColumn(report, cc); if (cc.IsModified == false) { cell2.DataBindings.Add("Text", null, columns[i].FieldName, "{0:" + columns[i].GridViewColumn.DisplayFormat + "}"); } detailsInfo.Add(columns[i].GridViewColumn, cell2); row2.Cells.Add(cell2); detailsWidth.Add(columns[i].GridViewColumn, cell2.WidthF); } } if (CustomizeFormattingRules != null) CustomizeFormattingRules(report, new CustomFormattingRulesEventArgs { Rules = report.FormattingRuleSheet }); foreach (var rule in report.FormattingRuleSheet) detailTable.FormattingRules.Add(rule); headerTable.Rows.Add(row); headerTable.Width = pagewidth; headerTable.LocationF = new PointF(groupedColumns.Count * subGroupOffset, 0); headerTable.Borders = DevExpress.XtraPrinting.BorderSide.Bottom; detailTable.Rows.Add(row2); detailTable.LocationF = new PointF(groupedColumns.Count * subGroupOffset, 0); detailTable.Width = pagewidth; report.Bands[BandKind.PageHeader].Controls.Add(headerTable); report.Bands[BandKind.Detail].Controls.Add(detailTable); } private void InitDetailReports(MVCxGridViewState gridViewState) { var groupedColumns = gridViewState.GroupedColumns; var pagewidth = (report.PageWidth - (report.Margins.Left + report.Margins.Right)) - groupedColumns.Count * subGroupOffset - detaillOffset; var columns = GetColumnsInfo(gridViewState, pagewidth); if (CustomizeColumnsCollection != null) CustomizeColumnsCollection(report, new ColumnsCreationEventArgs(pagewidth) { ColumnsInfo = columns }); var detailColumns = columns .Where(c => c.IsDetail) .ToList(); if (!detailColumns.Any()) return; var detailReportBand = new DetailReportBand() { HeightF = bandHeight }; report.Bands.Add(detailReportBand); var detailReportTable = new XRTable { StyleName = "DetailRowTable", OddStyleName = "DetailRow", EvenStyleName = "DetailRow", WidthF = pagewidth }; var detailReportRow = new XRTableRow(); foreach (var detailColumn in detailColumns) { var cellDetail = new XRTableCell { WidthF = pagewidth / detailColumns.Count, StyleName = "DetailRowCell" }; var label = new XRLabel { StyleName = "DetailRowLabel", WidthF = pagewidth / detailColumns.Count, WordWrap = true, Multiline = true }; label.DataBindings.Add("Text", null, detailColumn.FieldName, detailColumn.ColumnCaption + ":\n{0:" + detailColumn.GridViewColumn.DisplayFormat + "}"); cellDetail.Controls.Add(label); detailReportRow.Cells.Add(cellDetail); } detailReportTable.Rows.Add(detailReportRow); detailReportTable.LocationF = new PointF(groupedColumns.Count * subGroupOffset + detaillOffset, 0); DetailBand detailBand = new DetailBand(); detailBand.Height = detailReportTable.Height; detailReportBand.Bands.Add(detailBand); detailBand.Controls.Add(detailReportTable); } private void InitSortings(MVCxGridViewState gridViewState) { var columns = gridViewState.Columns; var groupedColumns = gridViewState.GroupedColumns; for (var i = 0; i < columns.Count; i++) { if (!groupedColumns.Contains(columns[i])) { if (columns[i].SortOrder != ColumnSortOrder.None) ((DetailBand)report.Bands[BandKind.Detail]).SortFields.Add(new GroupField(columns[i].FieldName, columns[i].SortOrder == ColumnSortOrder.Ascending ? XRColumnSortOrder.Ascending : XRColumnSortOrder.Descending)); } } } private void InitGroupHeaders(MVCxGridViewState gridViewState) { var groupedColumns = gridViewState.GroupedColumns; for (var i = groupedColumns.Count - 1; i >= 0; i--) { var groupedColumn = groupedColumns[i]; var gb = new GroupHeaderBand { Height = bandHeight }; var groupHeaderTable = new XRTable { StyleName = "GroupHeader", LocationF = new PointF(initialGroupOffset + i * 10, 0), SizeF = new SizeF((report.PageWidth - (report.Margins.Left + report.Margins.Right)) - (initialGroupOffset + i * subGroupOffset), bandHeight) }; var groupHeaderRow = new XRTableRow(); var l = new XRTableCell { Text = groupedColumn.Caption + ": [" + groupedColumn.FieldName + "]", Borders = DevExpress.XtraPrinting.BorderSide.Left | DevExpress.XtraPrinting.BorderSide.Top | DevExpress.XtraPrinting.BorderSide.Bottom }; groupHeaderRow.Cells.Add(l); foreach (MVCxSummaryItemState item in gridViewState.TotalSummary) { var sum = new XRTableCell { Borders = DevExpress.XtraPrinting.BorderSide.Top | DevExpress.XtraPrinting.BorderSide.Bottom }; sum.Summary = new XRSummary { Running = SummaryRunning.Group }; sum.Summary.Func = GetSummaryFunc(item.SummaryType); sum.DataBindings.Add("Text", null, item.FieldName); groupHeaderRow.Cells.Add(sum); if (CustomizeGroupColumnSummary != null) CustomizeGroupColumnSummary(report, new ColumnSummaryCreationEventArgs(item.FieldName, sum.Summary)); } groupHeaderTable.Rows.Add(groupHeaderRow); gb.Controls.Add(groupHeaderTable); gb.RepeatEveryPage = shouldRepeatGroupHeadersOnEveryPage; var gf = new GroupField( groupedColumn.FieldName, groupedColumn.SortOrder == ColumnSortOrder.Ascending ? XRColumnSortOrder.Ascending : XRColumnSortOrder.Descending); gb.GroupFields.Add(gf); report.Bands.Add(gb); } } private void InitFilters(MVCxGridViewState gridViewState) { report.FilterString = gridViewState.FilterExpression; } private void InitPageSummaries(MVCxGridViewState gridViewState) { if (gridViewState.TotalSummary.Count == 0) return; report.Bands.Add(new PageFooterBand { HeightF = bandHeight, StyleName = "SummaryRow", PrintOn = PrintOnPages.NotWithReportFooter }); foreach (MVCxSummaryItemState item in gridViewState.TotalSummary) { var col = gridViewState.Columns[item.ShowInColumn == string.Empty ? item.FieldName : item.ShowInColumn]; if (col == null) continue; if (!detailsInfo.Contains(col)) continue; var label = new XRLabel { LocationF = new PointF( ((XRTableCell)detailsInfo[col]).LocationF.X + subGroupOffset * gridViewState.GroupedColumns.Count, ((XRTableCell)detailsInfo[col]).LocationF.Y), SizeF = ((XRTableCell)detailsInfo[col]).SizeF }; label.Summary = new XRSummary { Running = SummaryRunning.Page }; label.Summary.FormatString = item.DisplayFormat; label.Summary.Func = GetSummaryFunc(item.SummaryType); label.DataBindings.Add("Text", null, col.FieldName); label.Tag = item.FieldName; if (PageSummaryGetResult != null) label.SummaryGetResult += PageSummaryGetResult; report.Bands[BandKind.PageFooter].Controls.Add(label); if (CustomizeTotalColumnSummary != null) CustomizeTotalColumnSummary(report, new ColumnSummaryCreationEventArgs(col.FieldName, label.Summary)); } } private void InitTotalSummaries(MVCxGridViewState gridViewState) { if (gridViewState.TotalSummary.Count == 0) return; report.Bands.Add(new ReportFooterBand { HeightF = bandHeight, StyleName = "SummaryRow" }); foreach (MVCxSummaryItemState item in gridViewState.TotalSummary) { var col = gridViewState.Columns[item.ShowInColumn == string.Empty ? item.FieldName : item.ShowInColumn]; if (col == null) continue; if (!detailsInfo.Contains(col)) continue; var label = new XRLabel { LocationF = new PointF( ((XRTableCell)detailsInfo[col]).LocationF.X + subGroupOffset * gridViewState.GroupedColumns.Count, ((XRTableCell)detailsInfo[col]).LocationF.Y), SizeF = ((XRTableCell)detailsInfo[col]).SizeF }; label.DataBindings.Add("Text", null, col.FieldName); label.Summary = new XRSummary { Running = SummaryRunning.Report }; label.Summary.FormatString = item.DisplayFormat; label.Summary.Func = GetSummaryFunc(item.SummaryType); label.Tag = item.FieldName; if (item.SummaryType == SummaryItemType.Custom) { label.SummaryReset += (source, e) => { if (SummaryReset != null) SummaryReset(report, new CustomSummaryResetEventArgs { FieldName = item.FieldName }); }; label.SummaryRowChanged += (source, e) => { if (SummaryRowChanged != null) SummaryRowChanged(report, new CustomSummaryRowChangedEventArgs { FieldName = item.FieldName }); }; } if (TotalSummaryGetResult != null) label.SummaryGetResult += TotalSummaryGetResult; report.Bands[BandKind.ReportFooter].Controls.Add(label); if (CustomizeTotalColumnSummary != null) CustomizeTotalColumnSummary(report, new ColumnSummaryCreationEventArgs(col.FieldName, label.Summary)); } } private void InitPageFooter() { var userHelper = Singleton.Instance.Resolve(); var user = userHelper.FromCookies(); report.Bands.Add(new BottomMarginBand { HeightF = 46f }); var footerTable = new XRTable { WidthF = (report.PageWidth - (report.Margins.Left + report.Margins.Right)), HeightF = 23f, Borders = DevExpress.XtraPrinting.BorderSide.Top, StyleName = "FooterRow" }; var footerRow = new XRTableRow { Cells = { new XRTableCell { TextAlignment = TextAlignment.MiddleLeft, Text = DateTime.Now.ToString("dd.MM.yyyy - HH:mm \"Uhr\" |"), WidthF = 145f, HeightF = 23f }, new XRTableCell { Controls = { new XRPageInfo { TextAlignment = TextAlignment.MiddleLeft, Format = "Seite {0} von {1}", PageInfo = PageInfo.NumberOfTotal, StartPageNumber = 1, Padding = 5, HeightF = 23f } }, WidthF = 100f, HeightF = 23f }, new XRTableCell { TextAlignment = TextAlignment.MiddleRight, Text = String.Format("{0}, {1}", user.Lastname, user.Forename), WidthF = (report.PageWidth - (report.Margins.Left + report.Margins.Right)) - 230 } } }; footerTable.Rows.Add(footerRow); report.Bands[BandKind.BottomMargin].Controls.Add(footerTable); } private List GetColumnsInfo(MVCxGridViewState gridViewState, int pagewidth) { var columns = new List(); var visibleColumns = gridViewState.Columns; foreach (var dataColumn in visibleColumns) { MVCxColumnInfo column = new MVCxColumnInfo(dataColumn) { ColumnCaption = string.IsNullOrEmpty(dataColumn.Caption) ? dataColumn.FieldName : dataColumn.Caption, ColumnWidth = ((int)pagewidth / visibleColumns.Count), FieldName = dataColumn.FieldName, IsVisible = true }; columns.Add(column); } return columns; } private SummaryFunc GetSummaryFunc(SummaryItemType summaryItemType) { switch (summaryItemType) { case SummaryItemType.Sum: return SummaryFunc.Sum; case SummaryItemType.Average: return SummaryFunc.Avg; case SummaryItemType.Max: return SummaryFunc.Max; case SummaryItemType.Min: return SummaryFunc.Min; case SummaryItemType.Count: return SummaryFunc.Count; default: return SummaryFunc.Custom; } } public void WritePdfToResponse(HttpResponseBase Response, string fileName, string type) { report.CreateDocument(false); using (MemoryStream ms = new MemoryStream()) { report.ExportToPdf(ms); ms.Seek(0, SeekOrigin.Begin); WriteResponse(Response, ms.ToArray(), "application/pdf", type, fileName); } } public void WriteXlsToResponse(HttpResponseBase Response, string fileName, string type) { report.CreateDocument(false); using (MemoryStream ms = new MemoryStream()) { report.ExportToXls(ms); ms.Seek(0, SeekOrigin.Begin); WriteResponse(Response, ms.ToArray(), "application/vnd.ms-excel", type, fileName); } } public void WriteXlsxToResponse(HttpResponseBase Response, string fileName, string type) { report.CreateDocument(false); using (MemoryStream ms = new MemoryStream()) { report.ExportToXlsx(ms); ms.Seek(0, SeekOrigin.Begin); WriteResponse(Response, ms.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", type, fileName); } } public static void WriteResponse(HttpResponseBase response, byte[] filearray, string contentType, string type, string fileName) { response.ClearContent(); response.Buffer = true; response.Cache.SetCacheability(HttpCacheability.Private); response.ContentType = contentType; ContentDisposition contentDisposition = new ContentDisposition(); contentDisposition.FileName = fileName; contentDisposition.DispositionType = type; response.AddHeader("Content-Disposition", contentDisposition.ToString()); response.BinaryWrite(filearray); HttpContext.Current.ApplicationInstance.CompleteRequest(); try { response.End(); } catch (System.Threading.ThreadAbortException) { } } } public class CustomFormattingRulesEventArgs : EventArgs { private FormattingRuleSheet rules; public FormattingRuleSheet Rules { get { return rules; } set { rules = value; } } } public class ControlCustomizationEventArgs : EventArgs { XRControl owner; public XRControl Owner { get { return owner; } set { owner = value; } } XRControl header; public XRControl Header { get { return header; } set { header = value; } } bool isModified; public bool IsModified { get { return isModified; } set { isModified = value; } } string fieldName; public string FieldName { get { return fieldName; } set { fieldName = value; } } } public class ColumnSummaryCreationEventArgs : EventArgs { public ColumnSummaryCreationEventArgs(string fieldName, XRSummary summary) { this.fieldName = fieldName; this.summary = summary; } XRSummary summary; public XRSummary Summary { get { return summary; } set { summary = value; } } string fieldName; public string FieldName { get { return fieldName; } set { fieldName = value; } } } public class ColumnsCreationEventArgs : EventArgs { int pageWidth; public int PageWidth { get { return pageWidth; } } public ColumnsCreationEventArgs(int pageWidth) { this.pageWidth = pageWidth; } List columnsInfo; public List ColumnsInfo { get { return columnsInfo; } set { columnsInfo = value; } } } public class CustomSummaryResetEventArgs : EventArgs { private string fieldName; public string FieldName { get { return fieldName; } set { fieldName = value; } } } public class CustomSummaryRowChangedEventArgs : EventArgs { private string fieldName; public string FieldName { get { return fieldName; } set { fieldName = value; } } } public class CustomSummaryGetResultEventArgs : SummaryGetResultEventArgs { public CustomSummaryGetResultEventArgs(IList calculatedValues) : base(calculatedValues) { } private string fieldName; public string FieldName { get { return fieldName; } set { fieldName = value; } } private XRControl control; public XRControl Control { get { return control; } set { control = value; } } } public class MVCxColumnInfo { public MVCxColumnInfo(GridViewDataColumnState gridViewColumn) { this.gridViewColumn = gridViewColumn; } GridViewDataColumnState gridViewColumn; public GridViewDataColumnState GridViewColumn { get { return gridViewColumn; } } string columnCaption; public string ColumnCaption { get { return columnCaption; } set { columnCaption = value; } } string fieldName; public string FieldName { get { return fieldName; } set { fieldName = value; } } int columnWidth; public int ColumnWidth { get { return columnWidth; } set { columnWidth = value; } } bool isVisible; public bool IsVisible { get { return isVisible; } set { isVisible = value; } } bool isDetail; public bool IsDetail { get { return isDetail; } set { isDetail = value; } } } } }