using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Drawing;
using
System.Drawing.Printing;
using
System.Windows.Forms;
using
System.Reflection;
using
System.Data;
using
System.IO;
namespace
Common
{
///
<summary>
///
通用打印模型(T-->列表數據的模型,該模型必須爲自定義的對象模型,嚴禁使用linq或其他工具生成的數據庫表模型,其中的各個字段均需要使用string類型)
///
</summary>
///
<typeparam name="T">列表數據的模型,該模型必須爲自定義的對象模型,嚴禁使用linq或其他工具生成的數據庫表模型,其中的各個字段均需要使用string類型</typeparam>
public
class
PrintDataModel<T>
{
///
<summary>
///
文檔標題
///
</summary>
public
string
pageTitle
{
get
;
set
;
}
///
<summary>
///
圖形數據
///
</summary>
public
Bitmap
extData {
get
;
set
;
}
///
<summary>
///
頭部的表頭數據(不包括文檔標題,如果沒有,應傳入 null;每個元素爲一行,如果一行無法容納,會換行處理。)
///
</summary>
public
List<
string
>
TitleData {
get
;
set
;
}
///
<summary>
///
頁面中間的列表數據(如果沒有,應傳入 null)
///
</summary>
public
List<T>
TableData {
get
;
set
;
}
///
<summary>
///
頁面中間的列表數據的表頭(與列表數據中的列一一對應,如果沒有(僅限列表數據傳入null的情況),應傳入 null)
///
</summary>
public
List<
string
>
ColumnNames {
get
;
set
;
}
///
<summary>
///
列表數據的各個列是否允許折行顯示,允許爲true,不允許爲false(僅當自動計算的列寬不足以顯示內容時生效,如果傳入null則表示所有列均允許折行顯示)
///
</summary>
public
List<
bool
>
CanResetLine {
get
;
set
;
}
///
<summary>
///
底部的結尾數據(不包括頁碼,如果沒有,應傳入 null;每個元素爲一行,如果一行無法容納,會換行處理。)
///
</summary>
public
List<
string
>
EndData {
get
;
set
;
}
}
///
<summary>
///
通用打印類(調用本類的方法是,請使用try-catch語句塊,內部錯誤消息將以異常的形式拋出)
///
</summary>
///
<typeparam name="T">列表數據的模型,該模型必須爲自定義的對象模型,嚴禁使用linq或其他工具生成的數據庫表模型,其中的各個字段均需要使用string類型</typeparam>
public
class
CommonPrintTools<T>
{
private
PrintDocument
docToPrint =
new
System.Drawing.Printing.PrintDocument();
///
<summary>
///
需打印的文檔數據
///
</summary>
private
List<PrintDataModel<T>>
_printDataModels;
///
<summary>
///
數據打印時的頁碼
///
</summary>
private
int
pageIndex
= 1;
///
<summary>
///
需要打印的文檔繪製出的圖片數據
///
</summary>
private
List<Bitmap>
_printBmps =
new
List<Bitmap>();
private
int
count
= 0;
///
<summary>
///
初始化打印類的各項參數
///
</summary>
///
<param name="PrintDataModels">需打印的文檔數據</param>
public
CommonPrintTools(List<PrintDataModel<T>>
PrintDataModels)
{
this
.docToPrint.PrintPage
+=
new
PrintPageEventHandler(docToPrint_PrintPage);
_printDataModels
= PrintDataModels;
}
///
<summary>
///
打印機開始打印的事件處理函數
///
</summary>
///
<param name="sender"></param>
///
<param name="e"></param>
private
void
docToPrint_PrintPage(
object
sender,
PrintPageEventArgs e)
{
Font
f =
new
Font(
"宋體"
,
10, FontStyle.Regular);
decimal
Chinese_OneWidth
= Convert.ToDecimal(e.Graphics.MeasureString(
"測"
,
f).Width);
int
pageWidth
= Convert.ToInt32(Math.Round(e.PageSettings.PrintableArea.Width, 0)) - 1;
int
onePageHeight
= Convert.ToInt32(Math.Round(e.PageSettings.PrintableArea.Height, 0)) - 1;
if
(_printBmps
==
null
||
_printBmps.Count <= 0)
_printBmps
= DrawPrintPic(e.Graphics, pageWidth, onePageHeight);
e.Graphics.DrawImage(_printBmps[count],
new
Rectangle((
int
)Math.Ceiling(Chinese_OneWidth),
0, _printBmps[count].Width, _printBmps[count].Height));
count++;
if
(_printBmps.Count
> count)
e.HasMorePages
=
true
;
else
e.HasMorePages
=
false
;
}
///
<summary>
///
繪製需打印的內容
///
</summary>
///
<param name="eventG"></param>
///
<param name="pageWidth"></param>
///
<param name="allPageHeight"></param>
///
<param name="msg"></param>
///
<returns></returns>
private
List<Bitmap>
DrawPrintPic(Graphics eventG,
int
pageWidth,
int
pageHeight)
{
Font
f =
new
Font(
"宋體"
,
10, FontStyle.Regular);
decimal
Chinese_OneWidth
= Convert.ToDecimal(eventG.MeasureString(
"測"
,
f).Width);
decimal
Chinese_OneHeight
= Convert.ToDecimal(eventG.MeasureString(
"測"
,
f).Height);
decimal
English_OneWidth
= Convert.ToDecimal(eventG.MeasureString(
"c"
,
f).Width);
decimal
English_OneHeight
= Convert.ToDecimal(eventG.MeasureString(
"c"
,
f).Height);
List<Bitmap>
bmpList =
new
List<Bitmap>();
foreach
(
var
pdm
in
_printDataModels)
{
Bitmap
bp =
new
Bitmap(pageWidth,
pageHeight);
Graphics
g = Graphics.FromImage(bp);
g.FillRectangle(Brushes.White,
0, 0, bp.Width, bp.Height);
List<T>
middleData = pdm.TableData;
List<
string
>
columnNames = pdm.ColumnNames;
List<
string
>
topData = pdm.TitleData;
List<
string
>
bottomData = pdm.EndData;
string
pageTitle
= pdm.pageTitle;
List<
bool
>
CanResetLine = pdm.CanResetLine;
Bitmap
codeBP = pdm.extData;
if
(middleData
!=
null
&&
middleData.Count > 0)
{
System.Reflection.PropertyInfo[]
pInfo = middleData[0].GetType().GetProperties();
if
(pInfo.Length
!= columnNames.Count)
{
throw
new
Exception(
"列表數據的列數與表頭數據的列數不相符!"
);
}
}
decimal
headEndHeight
= ComputeHeadEndHeight(pageTitle, topData, Chinese_OneHeight, pageWidth, g, f);
headEndHeight
+= ComputeHeadEndHeight(
null
,
bottomData, Chinese_OneHeight, pageWidth, g, f);
if
((headEndHeight
+ Chinese_OneHeight >= pageHeight) && middleData !=
null
&&
middleData.Count > 0)
{
throw
new
Exception(
"表頭或表尾數據太多,頁面中將沒有繪製數據行的空間!"
);
}
decimal
[]
columnWidths =
null
;
decimal
[]
rowHeights =
null
;
DataTable
dt =
new
DataTable();
if
(middleData
!=
null
&&
middleData.Count > 0)
{
string
msg
=
""
;
dt
= ReflactionToDataTable(middleData, columnNames,
ref
msg);
if
(dt
==
null
&&
!
string
.IsNullOrEmpty(msg))
{
throw
new
Exception(msg);
}
columnWidths
= GetColumnWidths(dt, CanResetLine, Chinese_OneWidth, g, f);
columnWidths
= GetColumnWidthToPage(columnWidths, pageWidth, Chinese_OneWidth, CanResetLine, g, f);
rowHeights
= GetRowHeights(dt, columnWidths, g, f);
}
if
(middleData
!=
null
&&
middleData.Count > 0 && dt !=
null
&&
dt.Rows.Count > 0)
{
bmpList.AddRange(DrawPage(pageWidth
- (
int
)Math.Ceiling(Chinese_OneWidth
* 2), pageHeight, f, Chinese_OneWidth, Chinese_OneHeight, topData, bottomData, pageTitle, codeBP, CanResetLine, rowHeights, dt, headEndHeight));
}
else
{
bmpList.AddRange(DrawPageWithOutDataTable(pageWidth
- (
int
)Math.Ceiling(Chinese_OneWidth
* 2), pageHeight, f, Chinese_OneHeight, topData, bottomData, pageTitle));
}
}
return
bmpList;
}
///
<summary>
///
繪製打印頁面
///
</summary>
///
<param name="pageWidth">頁面寬度</param>
///
<param name="pageHeight">頁面高度</param>
///
<param name="f">字體</param>
///
<param name="Chinese_OneWidth">單字寬度</param>
///
<param name="Chinese_OneHeight">單字高度</param>
///
<param name="topData">頭部的表頭數據(不包括文檔標題)</param>
///
<param name="bottomData">底部的結尾數據(不包括頁碼)</param>
///
<param name="pageTitle">文檔標題</param>
///
<param name="columnWidths">列寬度集合</param>
///
<param name="rowHeights">行高集合</param>
///
<param name="dt">需打印的所有列表數據</param>
///
<returns>所有需要打印的頁面</returns>
private
List<Bitmap>
DrawPage(
int
pageWidth,
int
pageHeight,
Font f,
decimal
Chinese_OneWidth,
decimal
Chinese_OneHeight,
List<
string
>
topData, List<
string
>
bottomData,
string
pageTitle,
Bitmap codeBP, List<
bool
>
CanResetLine,
decimal
[]
rowHeights, DataTable dt,
decimal
headEndHeight)
{
List<Bitmap>
bmpList =
new
List<Bitmap>();
List<DataTable>
dts = GetDataTableToPages(dt, rowHeights, pageHeight - headEndHeight - Chinese_OneHeight);
int
sourceRowIndex
= 1;
int
sourceRowIndexForCompute
= 1;
int
pageIndex
= 1;
foreach
(DataTable
drawDt
in
dts)
{
Bitmap
bpItem =
new
Bitmap(pageWidth,
pageHeight);
Graphics
gItem = Graphics.FromImage(bpItem);
decimal
[]
columnWidths = GetColumnWidths(drawDt, CanResetLine, Chinese_OneWidth, gItem, f);
columnWidths
= GetColumnWidthToPage(columnWidths, pageWidth, Chinese_OneWidth, CanResetLine, gItem, f);
gItem.FillRectangle(Brushes.White,
0, 0, bpItem.Width, bpItem.Height);
decimal
currentMarginTop
= 0;
if
(!
string
.IsNullOrEmpty(pageTitle))
{
currentMarginTop
+= Chinese_OneHeight;
List<
string
>
drawValues = GetMultiLineString(pageTitle, pageWidth, gItem, f);
foreach
(
string
dv
in
drawValues)
{
gItem.DrawString(dv,
f, Brushes.Black, (
float
)(pageWidth
- (
decimal
)gItem.MeasureString(dv,
f).Width) / 2, (
float
)currentMarginTop);
currentMarginTop
+= Chinese_OneHeight;
}
}
if
(codeBP
!=
null
&&
codeBP.Height > 0 && codeBP.Width > 0)
{
gItem.DrawImage(codeBP,
0, (
float
)currentMarginTop);
currentMarginTop
+= codeBP.Height;
}
if
(topData
!=
null
&&
topData.Count > 0)
{
foreach
(
string
tdTitle
in
topData)
{
currentMarginTop
+= Chinese_OneHeight/2;
List<
string
>
drawValues = GetMultiLineString(tdTitle, pageWidth, gItem, f);
foreach
(
string
dv
in
drawValues)
{
gItem.DrawString(dv,
f, Brushes.Black, 0, (
float
)currentMarginTop);
currentMarginTop
+= Chinese_OneHeight;
}
}
}
decimal
colLeft
= 0;
decimal
drawDtHeight
= rowHeights[0];
for
(
int
rowIndex
= 0; rowIndex < drawDt.Rows.Count; rowIndex++)
{
drawDtHeight
+= rowHeights[sourceRowIndexForCompute];
sourceRowIndexForCompute++;
}
currentMarginTop
+= Chinese_OneHeight / 2;
for
(
int
colIndex
= 0; colIndex < drawDt.Columns.Count; colIndex++)
{
string
colName
= drawDt.Columns[colIndex].ColumnName;
List<
string
>
drawValues = GetMultiLineString(colName, (
float
)columnWidths[colIndex],
gItem, f);
decimal
rowMarginTop
= currentMarginTop;
foreach
(
string
dv
in
drawValues)
{
gItem.DrawString(dv,
f, Brushes.Black, (
float
)colLeft,
(
float
)rowMarginTop);
rowMarginTop
+= Chinese_OneHeight;
}
gItem.DrawLine(
new
Pen(Brushes.Black),
new
Point((
int
)Math.Ceiling(colLeft),
(
int
)Math.Floor(currentMarginTop)
- 1),
new
Point((
int
)Math.Ceiling(colLeft),
(
int
)Math.Ceiling(currentMarginTop
+ drawDtHeight) - 2));
colLeft
+= columnWidths[colIndex];
}
gItem.DrawLine(
new
Pen(Brushes.Black),
new
Point(0,
(
int
)Math.Floor(currentMarginTop)
- 1),
new
Point((
int
)Math.Ceiling(columnWidths.Sum()
- 2), (
int
)Math.Floor(currentMarginTop)
- 1));
gItem.DrawLine(
new
Pen(Brushes.Black),
new
Point((
int
)Math.Ceiling(columnWidths.Sum()
- 2), (
int
)Math.Floor(currentMarginTop)
- 1),
new
Point((
int
)Math.Ceiling(columnWidths.Sum()
- 2), (
int
)Math.Ceiling(currentMarginTop
+ drawDtHeight) - 2));
currentMarginTop
+= rowHeights[0];
for
(
int
rowIndex
= 0; rowIndex < drawDt.Rows.Count; rowIndex++)
{
decimal
rowMarginLeft
= 0;
for
(
int
colIndex
= 0; colIndex < dt.Columns.Count; colIndex++)
{
string
drawValue
= drawDt.Rows[rowIndex][colIndex].ToString();
List<
string
>
drawValues = GetMultiLineString(drawValue, (
float
)columnWidths[colIndex],
gItem, f);
decimal
rowMarginTop
= currentMarginTop;
foreach
(
string
dv
in
drawValues)
{
gItem.DrawString(dv,
f, Brushes.Black, (
float
)rowMarginLeft,
(
float
)rowMarginTop);
rowMarginTop
+= Chinese_OneHeight;
}
rowMarginLeft
+= columnWidths[colIndex];
}
gItem.DrawLine(
new
Pen(Brushes.Black),
new
Point(0,
(
int
)Math.Floor(currentMarginTop)
- 1),
new
Point((
int
)Math.Ceiling(columnWidths.Sum()
- 2), (
int
)Math.Floor(currentMarginTop)
- 1));
currentMarginTop
+= rowHeights[sourceRowIndex];
sourceRowIndex++;
}
gItem.DrawLine(
new
Pen(Brushes.Black),
new
Point(0,
(
int
)Math.Floor(currentMarginTop)
- 1),
new
Point((
int
)Math.Ceiling(columnWidths.Sum()
- 2), (
int
)Math.Floor(currentMarginTop)
- 1));
if
(bottomData
!=
null
&&
bottomData.Count > 0)
{
currentMarginTop
+= Chinese_OneHeight / 2;
foreach
(
string
bdData
in
bottomData)
{
decimal
rowMarginTop
= currentMarginTop;
List<
string
>
drawValues = GetMultiLineString(bdData, (
float
)pageWidth,
gItem, f);
foreach
(
string
dv
in
drawValues)
{
gItem.DrawString(dv,
f, Brushes.Black, 0, (
float
)rowMarginTop);
rowMarginTop
+= Chinese_OneHeight;
}
currentMarginTop
+= Chinese_OneHeight;
}
}
string
pageInfo
=
string
.Format(
"當前第{0}頁,共{1}頁"
,
pageIndex.ToString(), dts.Count.ToString());
gItem.DrawString(pageInfo,
f, Brushes.Black, (
float
)(pageWidth
- (
decimal
)gItem.MeasureString(pageInfo,
f).Width - Chinese_OneWidth), (
float
)currentMarginTop);
bmpList.Add(bpItem);
pageIndex++;
}
return
bmpList;
}
///
<summary>
///
繪製打印頁面(無數據列表)
///
</summary>
///
<param name="pageWidth"></param>
///
<param name="pageHeight"></param>
///
<param name="f"></param>
///
<param name="Chinese_OneWidth"></param>
///
<param name="Chinese_OneHeight"></param>
///
<param name="topData"></param>
///
<param name="bottomData"></param>
///
<param name="pageTitle"></param>
///
<returns></returns>
private
List<Bitmap>
DrawPageWithOutDataTable(
int
pageWidth,
int
pageHeight,
Font f,
decimal
Chinese_OneHeight,
List<
string
>
topData, List<
string
>
bottomData,
string
pageTitle)
{
List<Bitmap>
bmpList =
new
List<Bitmap>();
List<
string
>
drawList =
new
List<
string
>();
if
(topData
!=
null
&&
topData.Count > 0)
drawList.AddRange(topData);
if
(bottomData
!=
null
&&
bottomData.Count > 0)
drawList.AddRange(bottomData);
Bitmap
bp =
new
Bitmap(pageWidth,
pageHeight);
Graphics
g = Graphics.FromImage(bp);
decimal
dataHeight
= pageHeight - Chinese_OneHeight;
if
(!
string
.IsNullOrEmpty(pageTitle))
{
decimal
titleHeight
= 0;
List<
string
>
titles = GetMultiLineString(pageTitle, pageWidth, g, f);
foreach
(
string
t
in
titles)
{
titleHeight
+= (
decimal
)g.MeasureString(t,
f).Width;
}
dataHeight
= (
decimal
)pageHeight
- titleHeight - Chinese_OneHeight;
}
List<List<
string
>>
drawData = GetLinesToPages(drawList, Chinese_OneHeight, dataHeight, pageWidth, g, f);
foreach
(List<
string
>
drawD
in
drawData)
{
Bitmap
bpItem =
new
Bitmap(pageWidth,
pageHeight);
Graphics
gItem = Graphics.FromImage(bpItem);
gItem.FillRectangle(Brushes.White,
0, 0, bpItem.Width, bpItem.Height);
decimal
currentMarginTop
= 0;
if
(!
string
.IsNullOrEmpty(pageTitle))
{
currentMarginTop
+= Chinese_OneHeight;
List<
string
>
drawValues = GetMultiLineString(pageTitle, pageWidth, gItem, f);
foreach
(
string
dv
in
drawValues)
{
gItem.DrawString(dv,
f, Brushes.Black, (
float
)(pageWidth
- (
decimal
)gItem.MeasureString(dv,
f).Width) / 2, (
float
)currentMarginTop);
currentMarginTop
+= Chinese_OneHeight;
}
}
foreach
(
string
dv
in
drawD)
{
gItem.DrawString(dv,
f, Brushes.Black, 0, (
float
)currentMarginTop);
currentMarginTop
+= Chinese_OneHeight;
}
string
pageInfo
=
string
.Format(
"當前第{0}頁,共{1}頁"
,
pageIndex.ToString(), drawData.Count.ToString());
gItem.DrawString(pageInfo,
f, Brushes.Black, 0, (
float
)currentMarginTop);
bmpList.Add(bpItem);
pageIndex++;
}
return
bmpList;
}
///
<summary>
///
開始打印
///
</summary>
///
<param name="printname">計算機上已安裝的打印機的名稱</param>
public
void
StartPrint(
string
printname)
{
System.Windows.Forms.PrintDialog
PrintDialog1 =
new
PrintDialog();
PrintDialog1.AllowSomePages
=
true
;
PrintDialog1.ShowHelp
=
true
;
PrintDialog1.Document
= docToPrint;
docToPrint.PrinterSettings.PrinterName
= printname;
docToPrint.Print();
}
///
<summary>
///
打印預覽
///
</summary>
///
<param name="dt">要打印的DataTable</param>
///
<param name="Title">打印文件的標題</param>
public
void
PrintPriview()
{
try
{
PrintPreviewDialog
PrintPriview =
new
PrintPreviewDialog();
PrintPriview.Document
= docToPrint;
PrintPriview.WindowState
= FormWindowState.Maximized;
PrintPriview.ShowDialog();
}
catch
(Exception
ex)
{
MessageBox.Show(
"打印錯誤,請檢查打印設置!消息:"
+
ex.Message);
}
}
public
void
TestPrint()
{
int
pageWidth
= 300;
int
onePageHeight
= 1000;
Bitmap
bp =
new
Bitmap(pageWidth,
onePageHeight);
Graphics
g = Graphics.FromImage(bp);
List<Bitmap>
bmps = DrawPrintPic(g, pageWidth, onePageHeight);
int
bmpName
= 1;
string
path
= Application.StartupPath +
"/pic"
;
List<
string
>
paths = Directory.GetFiles(path).ToList();
foreach
(
string
p
in
paths)
{
File.Delete(p);
}
foreach
(Bitmap
b
in
bmps)
{
if
(!Directory.Exists(path))
Directory.CreateDirectory(path);
b.Save(path
+
"/"
+
bmpName +
".jpg"
,
System.Drawing.Imaging.ImageFormat.Jpeg);
bmpName++;
}
}
///
<summary>
///
利用反射將數據對象集合轉換爲DataTable
///
</summary>
///
<typeparam name="T"></typeparam>
///
<param name="dataModel"></param>
///
<param name="columnNames"></param>
///
<returns></returns>
private
DataTable
ReflactionToDataTable<T>(List<T> dataModel, List<
string
>
columnNames,
ref
string
msg)
{
try
{
DataTable
dt =
new
DataTable();
if
(
typeof
(T).Equals(
typeof
(String)))
{
msg
=
"數據集合必須爲自定義對象集合!"
;
return
new
DataTable();
}
if
(dataModel
==
null
||
dataModel.Count <= 0)
{
msg
=
"傳入的數據集合爲空!"
;
return
new
DataTable();
}
if
(columnNames
==
null
||
columnNames.Count <= 0)
{
msg
=
"傳入的列名數據集合爲空!"
;
return
new
DataTable();
}
PropertyInfo[]
pInfos = ((
object
)dataModel[0]).GetType().GetProperties();
if
(pInfos.Length
!= columnNames.Count)
{
msg
=
"數據列數與列名數量不一致!"
;
return
new
DataTable();
}
for
(
int
i
= 0; i < columnNames.Count; i++)
{
dt.Columns.Add(columnNames[i],
pInfos[i].PropertyType);
}
for
(
int
i
= 0; i < dataModel.Count; i++)
{
object
[]
objArray =
new
object
[pInfos.Length];
for
(
int
j
= 0; j < pInfos.Length; j++)
{
object
ob
= pInfos[j].GetValue(dataModel[i],
null
);
objArray.SetValue(ob,
j);
}
dt.LoadDataRow(objArray,
true
);
}
return
dt;
}
catch
(Exception
ex)
{
msg
=
"請檢查傳入的數據類型,是否爲List<自定義對象>類型,自定義對象必須有屬性值!(異常信息:"
+
ex.Message +
")"
;
return
null
;
}
}
///
<summary>
///
講一個字符串按照固定的長度切分爲多個適合長度的字符串
///
</summary>
///
<param name="dataLine">需要切分的字符串</param>
///
<param name="width">固定的長度</param>
///
<param name="g">繪製對象</param>
///
<param name="f">字體</param>
///
<returns>切分後得到的字符串集合</returns>
private
List<
string
>
GetMultiLineString(
string
dataLine,
float
width,
Graphics g, Font f)
{
List<
string
>
dataLines =
new
List<
string
>();
char
[]
chars = dataLine.ToCharArray();
decimal
widthT
= Convert.ToDecimal(width);
decimal
charWidth
= Convert.ToDecimal(g.MeasureString(
"c"
.ToString(),
f).Width);
if
(widthT
< charWidth)
{
throw
new
Exception(
"數據無法正常顯示,經優化計算後的列寬不足以存放一個字符!"
);
}
decimal
widthC
= 0;
int
i
= 0;
string
dLine
=
""
;
string
tmpLine
=
""
;
while
(
true
)
{
if
(i
== chars.Length)
widthC
=
decimal
.MaxValue;
else
{
tmpLine
+= chars[i].ToString();
widthC
= Convert.ToDecimal(g.MeasureString(tmpLine, f).Width);
}
if
(widthC
< widthT)
{
dLine
= tmpLine;
}
else
{
dataLines.Add(dLine);
widthC
= 0;
dLine
=
""
;
tmpLine
=
""
;
if
(i
< chars.Length)
i--;
}
if
(i
>= chars.Length)
break
;
i++;
}
return
dataLines;
}
///
<summary>
///
獲取各個列的最大寬度值
///
</summary>
///
<param name="DataTablePrint">數據列表</param>
///
<param name="CanResetLine">各列是否允許折行顯示</param>
///
<param name="Chinese_OneWidth">單字寬度</param>
///
<param name="g">繪製對象</param>
///
<param name="f">字體</param>
///
<returns></returns>
private
decimal
[]
GetColumnWidths(DataTable DataTablePrint, List<
bool
>
CanResetLine,
decimal
Chinese_OneWidth,
Graphics g, Font f)
{
decimal
[]
res =
new
decimal
[DataTablePrint.Columns.Count];
;
foreach
(DataRow
dr
in
DataTablePrint.Rows)
{
for
(
int
i
= 0; i < DataTablePrint.Columns.Count; i++)
{
decimal
colwidth
= Convert.ToDecimal(g.MeasureString(dr[i].ToString().Trim(), f).Width) + (CanResetLine[i] ? 0 : Chinese_OneWidth / 2);
if
(colwidth
> res[i])
{
res[i]
= colwidth;
}
}
}
for
(
int
Cols
= 0; Cols <= DataTablePrint.Columns.Count - 1; Cols++)
{
string
ColumnText
= DataTablePrint.Columns[Cols].ColumnName.ToString();
decimal
colwidth
= Convert.ToInt32(g.MeasureString(ColumnText, f).Width) + (CanResetLine[Cols] ? 0 : Chinese_OneWidth / 2);
if
(colwidth
> res[Cols])
{
res[Cols]
= colwidth;
}
}
return
res;
}
///
<summary>
///
計算表頭部分高度
///
</summary>
///
<param name="pageTitle">頁面標題</param>
///
<param name="topData">表頭數據</param>
///
<param name="Chinese_OneHeight">單行高度</param>
///
<param name="pageWidth">頁面寬度</param>
///
<param name="g">繪製對象</param>
///
<param name="f">字體</param>
///
<returns></returns>
private
decimal
ComputeHeadEndHeight(
string
pageTitle,
List<
string
>
topData,
decimal
Chinese_OneHeight,
float
pageWidth,
Graphics g, Font f)
{
decimal
headHeight
= 0;
if
(!
string
.IsNullOrEmpty(pageTitle))
{
List<
string
>
pts = GetMultiLineString(pageTitle, pageWidth, g, f);
headHeight
+= Chinese_OneHeight;
headHeight
+= GetRowHeight(pts, g, f);
headHeight
+= Chinese_OneHeight;
}
if
(topData
!=
null
&&
topData.Count > 0)
{
foreach
(
string
tds
in
topData)
{
List<
string
>
tdss = GetMultiLineString(tds, pageWidth, g, f);
headHeight
+= GetRowHeight(tdss, g, f);
}
}
return
headHeight;
}
///
<summary>
///
獲取各個行的最大高度值(索引爲0的行高爲列標題的最大行高)
///
</summary>
///
<param name="dt">數據列表</param>
///
<param name="columnWidths">各個列的最大寬度值</param>
///
<param name="g">繪製對象</param>
///
<param name="f">字體</param>
///
<returns>返回行最大高度值集合</returns>
private
decimal
[]
GetRowHeights(DataTable dt,
decimal
[]
columnWidths, Graphics g, Font f)
{
decimal
[]
rowHeights =
new
decimal
[dt.Rows.Count
+ 1];
int
columnNameIndex
= 0;
foreach
(DataColumn
dc
in
dt.Columns)
{
string
dValue
= dc.ColumnName;
decimal
cwidth
= columnWidths[columnNameIndex];
List<
string
>
mLines = GetMultiLineString(dValue, (
float
)cwidth,
g, f);
decimal
h
= GetRowHeight(mLines, g, f);
if
(h
> rowHeights[0])
{
rowHeights[0]
= h;
}
columnNameIndex++;
}
int
columnIndex
= 0;
foreach
(DataColumn
dc
in
dt.Columns)
{
for
(
int
i
= 0; i < dt.Rows.Count; i++)
{
string
dValue
= dt.Rows[i][dc.ColumnName].ToString();
decimal
cwidth
= columnWidths[columnIndex];
List<
string
>
mLines = GetMultiLineString(dValue, (
float
)cwidth,
g, f);
decimal
h
= GetRowHeight(mLines, g, f);
if
(h
> rowHeights[i + 1])
{
rowHeights[i
+ 1] = h;
}
}
columnIndex++;
}
return
rowHeights;
}
///
<summary>
///
計算行高
///
</summary>
///
<param name="lines">一個DataRow需要顯示的行集合</param>
///
<param name="g">繪製對象</param>
///
<param name="f">字體</param>
///
<returns>返回DataRow行高</returns>
private
decimal
GetRowHeight(List<
string
>
lines, Graphics g, Font f)
{
decimal
h
= 0;
foreach
(
string
line
in
lines)
{
h
+= (
decimal
)g.MeasureString(line,
f).Height;
}
return
h;
}
///
<summary>
///
根據實際的列寬計算適應頁面所需的列寬度
///
</summary>
///
<param name="columnWidths">實際列寬</param>
///
<param name="pageWidth">頁面寬度</param>
///
<param name="Chinese_OneWidth">單字寬度</param>
///
<param name="CanResetLine">各列是否允許折行顯示</param>
///
<param name="g">繪製對象</param>
///
<param name="f">字體</param>
///
<returns>按比例計算之後的列寬</returns>
private
decimal
[]
GetColumnWidthToPage(
decimal
[]
columnWidths,
decimal
pageWidth,
decimal
Chinese_OneWidth,
List<
bool
>
CanResetLine, Graphics g, Font f)
{
string
cWidthString
=
""
;
for
(
int
i
= 0; i < columnWidths.Length; i++)
{
cWidthString
+=
"測"
;
}
if
(pageWidth
< (
decimal
)g.MeasureString(cWidthString,
f).Width)
{
throw
new
Exception(
"列數太多,當前紙張無法呈現(以每列一個漢字算,所有列的寬度之和,大於紙張寬度)!"
);
}
int
canResetCount
= 0;
decimal
solidWidth
= 0;
decimal
columnSumWidth
= columnWidths.Sum();
if
(CanResetLine
!=
null
&&
CanResetLine.Where(c => !c).Count() > 0)
{
columnSumWidth
= 0;
for
(
int
i
= 0; i < columnWidths.Length; i++)
{
if
(!CanResetLine[i])
{
solidWidth
+= columnWidths[i];
}
else
{
columnSumWidth
+= columnWidths[i];
canResetCount++;
}
}
pageWidth
-= solidWidth;
}
string
crWidthString
=
""
;
for
(
int
i
= 0; i < canResetCount; i++)
{
crWidthString
+=
"測"
;
}
if
((
decimal
)g.MeasureString(crWidthString,
f).Width > pageWidth)
{
throw
new
Exception(
"當前紙張無法呈現所有內容(以每列一個漢字算,所有可折行列的寬度之和,大於可以進行折行處理的剩餘總寬度)!"
);
}
decimal
[]
res =
new
decimal
[columnWidths.Length];
columnWidths.CopyTo(res,
0);
for
(
int
i
= 0; i < columnWidths.Length; i++)
{
if
(CanResetLine
==
null
||
CanResetLine[i])
res[i]
= (res[i] / columnSumWidth) * pageWidth;
}
return
res;
}
///
<summary>
///
獲取每頁的數據列表
///
</summary>
///
<param name="dt">所有列表數據</param>
///
<param name="rowHeights">行高集合</param>
///
<param name="dataHeight">顯示數據的可用高度</param>
///
<returns></returns>
private
List<DataTable>
GetDataTableToPages(DataTable dt,
decimal
[]
rowHeights,
decimal
dataHeight)
{
dataHeight
-= rowHeights[0];
List<DataTable>
dts =
new
List<DataTable>();
int
rowIndex
= 0;
decimal
currentHeight
= 0;
decimal
[]
rowHs =
new
decimal
[rowHeights.Length
- 1];
for
(
int
i
= 0; i < rowHs.Length; i++)
{
rowHs[i]
= rowHeights[i + 1];
}
List<DataRow>
drs =
new
List<DataRow>();
while
(rowIndex
<= dt.Rows.Count)
{
if
(rowIndex
== rowHs.Length)
{
DataTable
ndt = dt.Clone();
foreach
(DataRow
dr
in
drs)
{
DataRow
ndtDr = ndt.NewRow();
foreach
(DataColumn
dc
in
dt.Columns)
{
ndtDr[dc.ColumnName]
= dr[dc.ColumnName];
}
ndt.Rows.Add(ndtDr);
}
dts.Add(ndt);
break
;
}
if
((currentHeight
+ rowHs[rowIndex] > dataHeight))
{
DataTable
ndt = dt.Clone();
foreach
(DataRow
dr
in
drs)
{
DataRow
ndtDr = ndt.NewRow();
foreach
(DataColumn
dc
in
dt.Columns)
{
ndtDr[dc.ColumnName]
= dr[dc.ColumnName];
}
ndt.Rows.Add(ndtDr);
}
dts.Add(ndt);
rowIndex--;
currentHeight
= 0;
drs.Clear();
}
else
{
DataRow
dr = dt.NewRow();
for
(
int
i
= 0; i < dt.Columns.Count; i++)
{
dr[i]
= dt.Rows[rowIndex][i].ToString();
}
drs.Add(dr);
currentHeight
+= rowHs[rowIndex];
}
rowIndex++;
}
return
dts;
}
///
<summary>
///
獲取每頁的非數據列表的數據行
///
</summary>
///
<param name="data">所有數據行</param>
///
<param name="Chinese_OneHeight">單行高度</param>
///
<param name="dataHeight">顯示數據的可用高度</param>
///
<param name="pageWidth">頁面寬度</param>
///
<param name="g">繪製對象</param>
///
<param name="f">字體</param>
///
<returns></returns>
private
List<List<
string
>>
GetLinesToPages(List<
string
>
data,
decimal
Chinese_OneHeight,
decimal
dataHeight,
decimal
pageWidth,
Graphics g, Font f)
{
List<List<
string
>>
res =
new
List<List<
string
>>();
List<
string
>
resData =
new
List<
string
>();
decimal
currentHeight
= 0;
foreach
(
string
dLine
in
data)
{
List<
string
>
dvs = GetMultiLineString(dLine, (
float
)pageWidth,
g, f);
foreach
(
string
dv
in
dvs)
{
if
(currentHeight
+ Chinese_OneHeight > dataHeight)
{
res.Add(resData);
resData.Clear();
currentHeight
= 0;
resData.Add(dv);
currentHeight
+= Chinese_OneHeight;
}
else
{
resData.Add(dv);
currentHeight
+= Chinese_OneHeight;
}
}
}
return
res;
}
}
}