using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Documents; using System.Windows.Media; using System.Windows; using Utils.Datas; namespace Utils.Printers { public class DrawPage { public DrawPage() { _Headers = new List>(); _DetailRows = new List>(); } #region 变量、属性 public double FontSize_InforsBeforeHead { get; set; }//表前信息的字号 public IList InforsBeforeHead { get; set; }//表前信息 private double _PageWidth = 800; public double PageWidth { set { _PageWidth = value; } get { return _PageWidth; } }//页宽 public string Title { get; set; }//标题 private double _TitleFontSize = 20; public double TitleFontSize { set { _TitleFontSize = value; } get { return _TitleFontSize; } }//标题字号 private double _TitleMarginLeft = 20; public double TitleMarginLeft { set { _TitleMarginLeft = value; } get { return _TitleMarginLeft; } }//标题左边距 private double _MarginLeft = 20; public double MarginLeft { set { _MarginLeft = value; } get { return _MarginLeft; } }//左边距 private double _MarginTop = 20; public double MarginTop { set { _MarginTop = value; } get { return _MarginTop; } }//顶边距 private double _LineDistance = 4; public double LineDistance { set { _LineDistance = value; } get { return _LineDistance; } }//行距 private double _FontSize = 16; public double FontSize { set { _FontSize = value; } get { return _FontSize; } }//字号 private double _FontSize_Footer = 10; public double FontSize_Footer { set { _FontSize_Footer = value; } get { return _FontSize_Footer; } }//页脚字号 private Typeface _TypeFace = new Typeface("SimSun"); public Typeface TypeFace { set { _TypeFace = value; } get { return _TypeFace; } } private int _HeaderColumnsCount = 3; public int HeaderColumnsCount { set { _HeaderColumnsCount = value; } get { return _HeaderColumnsCount; } }//表头列数 private int _HeaderCharCount = 4; public int HeaderCharCount { set { _HeaderCharCount = value; } get { return _HeaderCharCount; } }//表头字数 private int _DetailMaxRows = 6; public int DetailMaxRows { set { _DetailMaxRows = value; } get { return _DetailMaxRows; } }//清单行数。超出则分页 public IList SumColumnNames { get; set; }//合计列的列名 public bool AllowSum { get; set; }//是否合计 public double FontSize_InforsBeforeFooter { get; set; } public double FontSize_InforsAfterFooter { get; set; } public IList InforsBeforeFooter { get; set; } public IList InforsAfterFooter { get; set; } private List> _Headers; private string[] _ColumnNames; private double[] _ColumnWidths; private int _DefaultWidth_CharCount = 4;//默认列宽(字数) private List> _DetailRows; public string Printer { get; set; }//打印人 public bool ShowPrinter { get; set; }//是否打印打印人 public bool ShowPrintTime { get; set; }//是否打印打印时间 public bool ShowPageNum { get; set; }//是否打印页码 #endregion /// /// 添加表头 /// 可多次添加。每次添加新起一行;一次添加的信息,如果达到最大列数,自动换行 /// public void AddHeaders(Dictionary headers) { Dictionary tmp = new Dictionary(); foreach (var item in headers) { tmp.Add(item.Key + ":", item.Value); } _Headers.Add(tmp); } /// /// 添加清单列名 /// public void AddColumnNames(params string[] columnNames) { _ColumnNames = columnNames; } /// /// 添加列宽。如果添加的列宽,没有列数多,则默认设置为_DefaultWidth_CharCount变量对应的字数的宽度。 /// public void SetColumnWidths(params double[] columnWidths) { _ColumnWidths = columnWidths; } /// /// 添加一行数据。该方法使用前提:先添加列名(AddColumnNames方法) /// public void AddRow(params string[] values)//前提条件:先添加列名 { #if DEBUG if (values == null || values.Count() == 0) throw new ApplicationException("AddRow(params string[] values)方法应该至少有一个参数"); if (_ColumnNames == null || _ColumnNames.Count() == 0) throw new ApplicationException("请先调用AddColumnNames方法添加列名"); #endif Dictionary row = new Dictionary(); for (int i = 0; i < _ColumnNames.Length; i++) { if (values.Length > i) row.Add(_ColumnNames.ElementAt(i), values.ElementAt(i)); } _DetailRows.Add(row); } /// /// 添加一行数据。 /// public void AddRow(Dictionary values) { #if DEBUG if (values == null || values.Count == 0) throw new ApplicationException("AddRow(Dictionary values)方法添加的列至少应该有一列"); #endif _DetailRows.Add(values); } /// /// 得到打印页面 /// /// 页的序号,从0开始 public DocumentPage GetPage(int pageIndex) { DrawingVisual visual = new DrawingVisual(); using (DrawingContext dc = visual.RenderOpen()) { //打印表前信息 double nextLineStartY = _MarginTop; if (InforsBeforeHead != null || InforsBeforeHead.Count > 0) nextLineStartY = DrawInfos(dc, FontSize_InforsBeforeHead, _MarginLeft, nextLineStartY, InforsBeforeHead.ToArray()); //打印标题 nextLineStartY = DrawTitle(dc, _TitleMarginLeft, nextLineStartY, Title, _TitleFontSize); //打印表头 nextLineStartY = DrawHeaders(dc, nextLineStartY); //打印清单列名 List columnWidthsAll; var columnWidthStartXs = GetColumnWidthsStartX(MarginLeft, _ColumnWidths, _ColumnNames.Length, out columnWidthsAll); DrawDetail(nextLineStartY, dc, _ColumnNames, columnWidthStartXs, columnWidthsAll, out nextLineStartY); //打印清单 if (_DetailRows != null && _DetailRows.Count > 0) { var rows = _DetailRows.Skip(pageIndex * DetailMaxRows); for (int i = 0; i < rows.Count(); i++) { if (i >= DetailMaxRows) break; var datas = PrepareRow(rows.ElementAt(i), _ColumnNames); DrawDetail(nextLineStartY, dc, datas, columnWidthStartXs, columnWidthsAll, out nextLineStartY); } } //打印合计 DrawSumRow(nextLineStartY, dc, columnWidthStartXs, columnWidthsAll, out nextLineStartY); //打印页脚前信息 if (InforsBeforeFooter != null || InforsBeforeFooter.Count > 0) nextLineStartY = DrawInfos(dc, FontSize_InforsBeforeFooter, _MarginLeft, nextLineStartY, InforsBeforeFooter.ToArray()); //打印页脚 nextLineStartY = DrawFooter(dc, nextLineStartY, pageIndex); //打印页脚后信息 if (InforsAfterFooter != null || InforsAfterFooter.Count > 0) nextLineStartY = DrawInfos(dc, FontSize_InforsAfterFooter, _MarginLeft, nextLineStartY, InforsAfterFooter.ToArray()); } return new DocumentPage(visual); } private double DrawTitle(DrawingContext dc, double startX, double startY, string Title, double titleFontSize) { double nextLineStartY; Point point = new Point(startX, startY); PrinterUtil.DrawText(point, dc, Title, titleFontSize, LineDistance, TypeFace, out nextLineStartY); return nextLineStartY; } private double DrawHeaders(DrawingContext dc, double startY) { double next = startY; foreach (var item in _Headers) { next = DrawPairsInfo(dc, item, FontSize, HeaderCharCount, HeaderColumnsCount, next); } return next; } private static List GetAverageWidthsStartX(double width, double marginLeft, int columnsCount) {//将宽度平均分成columnsCount份,返回每一份的起点 #if DEBUG if (columnsCount == 0) throw new ApplicationException("columnsCount参数不允许为0"); #endif List startXs = new List(); var start = marginLeft; startXs.Add(start); double averageLength = (width - marginLeft) / columnsCount; for (int i = 0; i < columnsCount - 1; i++) { start += averageLength; startXs.Add(start); } return startXs; } private List GetColumnWidthsStartX(double marginLeft, double[] columnWidths, int columnCount, out List columnWidthsAll) { columnWidthsAll = new List(); List widthsStartX = new List(); widthsStartX.Add(marginLeft); foreach (var c in columnWidths) { marginLeft += c; widthsStartX.Add(marginLeft); columnWidthsAll.Add(c); } if (columnWidths.Length < columnCount) { var width = PrinterUtil.GetWidth(_DefaultWidth_CharCount, FontSize, TypeFace); for (int i = 0; i < columnCount - columnWidths.Length; i++) { marginLeft += width; widthsStartX.Add(marginLeft); columnWidthsAll.Add(width); } } return widthsStartX; } private void DrawDetail(double startY, DrawingContext dc, IList values, List columnWidthStartXs, List columnWidthsAll, out double nextLineStartY)//前提条件:将values设置为与_ColumnNames对应起来 { nextLineStartY = startY; Point point = new Point(0, startY); for (int i = 0; i < values.Count; i++) { point.X = columnWidthStartXs.ElementAt(i); PrinterUtil.DrawTextWithRectangle(point, dc, values[i], FontSize, TypeFace, columnWidthsAll[i], 0.5, 5, LineDistance, out nextLineStartY); } } private void DrawSumDetail(double startY, DrawingContext dc, IList values, List columnWidthStartXs, List columnWidthsAll, out double nextLineStartY) { nextLineStartY = startY; Point point = new Point(0, startY); bool isBlack = false; for (int i = 0; i < values.Count; i++) { if (i == 0 && string.IsNullOrEmpty(values[i])) isBlack = true; if (isBlack && string.IsNullOrEmpty(values[i])) continue; if (isBlack) { isBlack = false; double width = 0; for (int j = 0; j < i; j++) { width += columnWidthsAll[j]; } double sumTextMagin = width + 5 - columnWidthsAll[i - 1]; point.X = columnWidthStartXs.ElementAt(0); PrinterUtil.DrawTextWithRectangle(point, dc, "合计", FontSize, TypeFace, width, 0.5, sumTextMagin, LineDistance, out nextLineStartY); } point.X = columnWidthStartXs.ElementAt(i); PrinterUtil.DrawTextWithRectangle(point, dc, values[i], FontSize, TypeFace, columnWidthsAll[i], 0.5, 5, LineDistance, out nextLineStartY); } } private void DrawSumRow(double startY, DrawingContext dc, List columnWidthStartXs, List columnWidthsAll, out double nextLineStartY) { if (!AllowSum) { nextLineStartY = startY; return; } List values = new List(); foreach (var name in _ColumnNames) { if (SumColumnNames.Contains(name)) { values.Add(GetSumValue(_DetailRows, name)); } else values.Add(string.Empty); } DrawSumDetail(startY, dc, values, columnWidthStartXs, columnWidthsAll, out nextLineStartY); } private string GetSumValue(List> detailRows, string name) { decimal sum = 0; foreach (var row in detailRows) { if (!row.Keys.Contains(name)) return string.Empty; if (string.IsNullOrEmpty(row[name])) continue; decimal value; if (decimal.TryParse(row[name], out value)) sum += value; else throw new ApplicationException("计算合计数据出错"); } //return sum.ToString("F2"); return NumToStringUtil.GetPointAtMost(sum); } private List PrepareRow(Dictionary row, string[] columnNames) { List result = new List(); foreach (var item in columnNames) { if (row.Keys.Contains(item)) result.Add(row[item]); else result.Add(string.Empty); } return result; } /// /// 绘制键值对信息 /// /// 键值对信息 /// 键的个数 /// 一行上,显示的键值对的个数 /// 起点Y坐标 /// 下一行的Y坐标 private double DrawPairsInfo(DrawingContext dc, Dictionary infos, double fontSize, int charCount_Key, int columnsCount, double startY)//返回下一行的Y坐标 { double nextLineStartY = startY; var charLength_Key = PrinterUtil.GetWidth(charCount_Key, fontSize, TypeFace); var averageWidths_StartX = GetAverageWidthsStartX(PageWidth, MarginLeft, columnsCount); Point point = new Point(averageWidths_StartX[0], nextLineStartY); for (int i = 0; i < infos.Count; i++) { var columnIndex = i % columnsCount; point.X = averageWidths_StartX[columnIndex]; if (columnIndex == 0 && i != 0) { point.Y = nextLineStartY; } PrinterUtil.DrawText(point, dc, infos.ElementAt(i).Key, fontSize, LineDistance, TypeFace); PrinterUtil.DrawText(new Point(point.X + charLength_Key, point.Y), dc, infos.ElementAt(i).Value, fontSize, LineDistance, TypeFace, out nextLineStartY); } return nextLineStartY; } private double DrawInfos(DrawingContext dc, double fontSize, double startX, double startY, params string[] infos) { if (infos == null || infos.Length == 0) return startY; double next = startY; Point point = new Point(startX, next); foreach (var item in infos) { PrinterUtil.DrawText(point, dc, item, fontSize, LineDistance, TypeFace, out next); point.Y = next; } return next; } private double DrawFooter(DrawingContext dc, double startY, int pageIndex) { if (!ShowPrinter && !ShowPrintTime && !ShowPageNum) return startY; Dictionary pairs = new Dictionary(); int charCount_Key = 5; int columnCount = 3; if (ShowPrinter) pairs.Add("打印人:", string.IsNullOrEmpty(Printer) ? string.Empty : Printer); if (ShowPrintTime) pairs.Add("打印时间:", DateTime.Now.ToString()); if (ShowPageNum) pairs.Add("第" + (pageIndex + 1) + "页", "共" + PageNumUtil.GetTotalPageCount(_DetailRows.Count, _DetailMaxRows) + "页"); return DrawPairsInfo(dc, pairs, FontSize_Footer, charCount_Key, columnCount, startY); } } }