最近需要用到WPF做一个报表
然后经过各种查阅资料
终于整出来了一个Demo
软件是VS2017 .netframework是4.5
1.配置环境
工具,获取扩展和更新
然后安装RDLC,然后重启
新建项目
项目的引用里面添加
System.Printing
System.Management
System.Drawing
NuGet包里面添加
Microsoft.ReportViewer V11.0.3366.16
2.创建实体类和数据集
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RDLCPrinter
{
public class Customer
{
public string carrierCompanyName { get; set; }
public string checkInTime { get; set; }
public string startPoint { get; set; }
public string outStock { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RDLCPrinter
{
class Plan
{
public string carrierCompanyName { get; set; } //承运单位
public string driver { get; set; } //司机
public string driverId { get; set; } //司机id
public string vehicleNo { get; set; } //车牌号
public string mobile { get; set; } //电话
public string planNo { get; set; } //调度单号
public string startPoint { get; set; } //装点
public string endPoint { get; set; } //卸点
public string flowName { get; set; } //流向
public string prodName { get; set; } //品名
public string planWeight { get; set; } //重量
public string planQuantity { get; set; } //件数
public string remark { get; set; } //备注
public string cardNo { get; set; }
public string planStatusName { get; set; }//签到状态
public string checkInTime { get; set; }//签到时间
public string scanDateTime { get; set; }//扫码日期和时间
public string scanTime { get; set; }//扫码时间
public string outStock { get; set; }//仓库
}
}
然后创建两个数据集
数据集里 右键 添加 DataTable把实体类的属性都加进去
或者
工具箱 双击DataTable
加完之后是这样的
然后创建一个rdlc
左边 新建 数据集
自己找到实体类,或者直接选择刚才创建好的DataSet.xsd
两个实体类都添加一下数据源
然后在rdlc文件 右键 插入 表
表里绑定一下属性
表头的汉字是自己加的
新建几个文本框 还有创建一个页眉
一个文本框绑定页数
另外的绑定另外一个实体类
具体的操作流程
在一个文本框上面右键
数据集->DataSet->然后选择属性双击
绑定页数同理,用的是内置字段->pageNumber双击,然后用一下字符串拼接
(这个感觉和Excel非常神似啊)
3.页面设计
MainWindow添加两个按钮,一个是打印预览的,一个是直接打印的
然后是RepoerViewer.xaml
这个需要注意的是
需要在头上加上这个
xmlns:rv="clr-namespace:Microsoft.Reporting.WinForms;assembly=Microsoft.ReportViewer.WinForms"
然后是整体的代码
然后新建一个CustomerReport.xaml
这个是打印预览界面
调一下刚才的ReportViewer
4.数据注入
这一步是最主要的
ReportViewer.cs注入打印预览界面的数据
然后mainWindow注入直接打印的数据
using System.Data;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Reporting.WinForms;
namespace RDLCPrinter
{
///
/// Interaction logic for ReportViewer.xaml
///
public partial class ReportViewer : UserControl
{
public ReportViewer()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
DataTable dt2 = new DataTable();
dt2.Columns.Add(new DataColumn("carrierCompanyName", typeof(string)));
dt2.Columns.Add(new DataColumn("checkInTime", typeof(string)));
dt2.Columns.Add(new DataColumn("startPoint", typeof(string)));
dt2.Columns.Add(new DataColumn("outStock", typeof(string)));
DataRow dr2 = dt2.NewRow();
dr2["carrierCompanyName"] = "日照钢铁";
dr2["checkInTime"] = "2019-8-13 16:03";
dr2["startPoint"] = "山东青岛";
dr2["outStock"] = "Z1-热轧#1580成品库";
dt2.Rows.Add(dr2);
ReportDataSource reportDataSource2 = new ReportDataSource();
reportDataSource2.Name = "DataSet1";
reportDataSource2.Value = dt2;
reportViewer1.LocalReport.DataSources.Add(reportDataSource2);
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("carrierCompanyName", typeof(string)));
dt.Columns.Add(new DataColumn("driverId", typeof(string)));
dt.Columns.Add(new DataColumn("startPoint", typeof(string)));
dt.Columns.Add(new DataColumn("endPoint", typeof(string)));
dt.Columns.Add(new DataColumn("prodName", typeof(string)));
dt.Columns.Add(new DataColumn("planQuantity", typeof(string)));
dt.Columns.Add(new DataColumn("checkInTime", typeof(string)));
dt.Columns.Add(new DataColumn("outStock", typeof(string)));
DataRow dr = dt.NewRow();
for (int i = 0; i < 20; i++)
{
dt.Rows.Add(new string[] { ("京创" + i).ToString(), (i + 10).ToString(), ("日照"+i).ToString(),
("山东" +i).ToString(),"卷钢" + i.ToString(),(10+i).ToString(),("2019-8-1"+i).ToString(), (i+"号").ToString()});
}
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "DataSet2";
reportDataSource.Value = dt;
reportViewer1.LocalReport.DataSources.Add(reportDataSource);
reportViewer1.LocalReport.ReportPath = "D:\\Documents\\GitHub\\DEMO\\RDLC\\RDLC\\CustomerReport.rdlc";
//刷新
reportViewer1.RefreshReport();
}
private void reportViewer_RenderingComplete(object sender, Microsoft.Reporting.WinForms.RenderingCompleteEventArgs e)
{
}
}
}
直接打印用到了一个工具类
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Reporting.WinForms;
namespace RDLCPrinter
{
///
/// 通过RDLC向默认打印机输出打印报表
///
public class BillPrint : IDisposable
{
///
/// 当前打印页号
///
static int m_currentPageIndex;
///
/// RDCL转换stream一页对应一个stream
///
static List m_streams;
///
/// 把report输出成stream
///
/// 传入需要Export的report
private void Export(LocalReport report)
{
string deviceInfo =
"" +
" EMF " +
//" 2in " +
//" 20in " +
" 1in " +
" 0in " +
" 0in " +
" 1in " +
" ";
Warning[] warnings;
m_streams = new List();
report.Render("Image", deviceInfo, CreateStream, out warnings);
foreach (Stream stream in m_streams)
stream.Position = 0;
}
///
/// 创建具有指定的名称和格式的流。
///
private Stream CreateStream(string name, string fileNameExtension,
Encoding encoding, string mimeType, bool willSeek)
{
Stream stream = new FileStream(name + "." + fileNameExtension,
FileMode.Create);
m_streams.Add(stream);
return stream;
}
///
/// 打印输出
///
private void PrintPage(object sender, PrintPageEventArgs ev)
{
Metafile pageImage =
new Metafile(m_streams[m_currentPageIndex]);
ev.Graphics.DrawImage(pageImage, ev.PageBounds);
m_currentPageIndex++;
ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
}
///
/// 打印预处理
///
private void Print()
{
PrintDocument printDoc = new PrintDocument();
string printerName = printDoc.PrinterSettings.PrinterName;
if (m_streams == null || m_streams.Count == 0)
return;
printDoc.PrinterSettings.PrinterName = printerName;
if (!printDoc.PrinterSettings.IsValid)
{
string msg = String.Format("Can't find printer \"{0}\".", printerName);
throw new Exception(msg);
}
printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
StandardPrintController spc = new StandardPrintController();
printDoc.PrintController = spc;
printDoc.Print();
}
public void Dispose()
{
if (m_streams != null)
{
foreach (Stream stream in m_streams)
stream.Close();
m_streams = null;
}
}
///
/// 对外接口,启动打印
///
/// 打印报表对应的数据源
/// 打印报表名称
public static void Run(LocalReport report)
{
//LocalReport report = new LocalReport();
//report.ReportPath = @"..\..\" + sReport;
//ReportDataSource dataset = new ReportDataSource("DataSet1", dtSource);
//report.DataSources.Add(dataset);
m_currentPageIndex = 0;
BillPrint billPrint = new BillPrint();
billPrint.Export(report);
billPrint.Print();
billPrint.Dispose();
}
///
/// 获取打印机状态
///
/// 打印机名称
/// 输出打印机状态
private static void GetPrinterStatus2(string printerName, ref uint status)
{
try
{
string lcPrinterName = printerName;
IntPtr liHandle = IntPtr.Zero;
if (!Win32.OpenPrinter(lcPrinterName, out liHandle, IntPtr.Zero))
{
Console.WriteLine("print is close");
return;
}
UInt32 level = 2;
UInt32 sizeNeeded = 0;
IntPtr buffer = IntPtr.Zero;
Win32.GetPrinter(liHandle, level, buffer, 0, out sizeNeeded);
buffer = Marshal.AllocHGlobal((int)sizeNeeded);
if (!Win32.GetPrinter(liHandle, level, buffer, sizeNeeded, out sizeNeeded))
{
Console.WriteLine(Environment.NewLine + "Fail GetPrinter:" + Marshal.GetLastWin32Error());
return;
}
Win32.PRINTER_INFO_2 info = (Win32.PRINTER_INFO_2)Marshal.PtrToStructure(buffer, typeof(Win32.PRINTER_INFO_2));
status = info.Status;
Marshal.FreeHGlobal(buffer);
Win32.ClosePrinter(liHandle);
}
catch (Exception ex)
{
throw ex;
}
}
///
/// 对外接口,调去打印机信息
///
/// 打印机名称
/// 返回打印机当前状态
public static string GetPrinterStatus(string printerName)
{
uint intValue = 0;
PrintDocument pd = new PrintDocument();
printerName = printerName == "" ? pd.PrinterSettings.PrinterName : printerName;
GetPrinterStatus2(printerName, ref intValue);
string strRet = string.Empty;
switch (intValue)
{
case 0:
strRet = "准备就绪(Ready)";
break;
case 4194432:
strRet = "被打开(Lid Open)";
break;
case 144:
strRet = "打印纸用完(Out of Paper)";
break;
case 4194448:
strRet = "被打开并且打印纸用完(Out of Paper && Lid Open)";
break;
case 1024:
strRet = "打印中(Printing)";
break;
case 32768:
strRet = "初始化(Initializing)";
break;
case 160:
strRet = "手工送纸(Manual Feed in Progress)";
break;
case 4096:
strRet = "脱机(Offline)";
break;
default:
strRet = "未知状态(unknown state)";
break;
}
return strRet;
}
}
public class Win32
{
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool OpenPrinter(string printer, out IntPtr handle, IntPtr printerDefaults);
[DllImport("winspool.drv")]
public static extern bool ClosePrinter(IntPtr handle);
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GetPrinter(IntPtr handle, UInt32 level, IntPtr buffer, UInt32 size, out UInt32 sizeNeeded);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PRINTER_INFO_2
{
public string pServerName;
public string pPrinterName;
public string pShareName;
public string pPortName;
public string pDriverName;
public string pComment;
public string pLocation;
public IntPtr pDevMode;
public string pSepFile;
public string pPrintProcessor;
public string pDatatype;
public string pParameters;
public IntPtr pSecurityDescriptor;
public UInt32 Attributes;
public UInt32 Priority;
public UInt32 DefaultPriority;
public UInt32 StartTime;
public UInt32 UntilTime;
public UInt32 Status;
public UInt32 cJobs;
public UInt32 AveragePPM;
}
}
}
判断打印机状态好像没啥用
最后是MainWindow的数据
using Microsoft.Reporting.WinForms;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace RDLCPrinter
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnClickMe_Click(object sender, RoutedEventArgs e)
{
CustomerReport rpt = new CustomerReport();
rpt.ShowDialog();
}
//打印
private void Button_Print_Click(object sender, RoutedEventArgs e)
{
ReportViewer rvDoc = new ReportViewer();
DataTable dt2 = new DataTable();
dt2.Columns.Add(new DataColumn("carrierCompanyName", typeof(string)));
dt2.Columns.Add(new DataColumn("checkInTime", typeof(string)));
dt2.Columns.Add(new DataColumn("startPoint", typeof(string)));
dt2.Columns.Add(new DataColumn("outStock", typeof(string)));
DataRow dr2 = dt2.NewRow();
dr2["carrierCompanyName"] = "日照钢铁";
dr2["checkInTime"] = "2019-8-13 16:03";
dr2["startPoint"] = "山东青岛";
dr2["outStock"] = "Z1-热轧#1580成品库";
dt2.Rows.Add(dr2);
ReportDataSource reportDataSource2 = new ReportDataSource();
reportDataSource2.Name = "DataSet1";
reportDataSource2.Value = dt2;
rvDoc.reportViewer1.LocalReport.DataSources.Add(reportDataSource2);
//rvDoc.reportViewer1
//rvDoc.reportViewer1.LocalReport.DataSources.Add(reportDataSource2);
rvDoc.reportViewer1.LocalReport.ReportPath = @"D:\\Documents\\GitHub\\DEMO\\RDLC\\RDLC\\CustomerReport.rdlc";
//rvDoc.reportViewer1.RefreshReport();
/*自动打印*/
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("carrierCompanyName", typeof(string)));
dt.Columns.Add(new DataColumn("driverId", typeof(string)));
dt.Columns.Add(new DataColumn("startPoint", typeof(string)));
dt.Columns.Add(new DataColumn("endPoint", typeof(string)));
dt.Columns.Add(new DataColumn("prodName", typeof(string)));
dt.Columns.Add(new DataColumn("planQuantity", typeof(string)));
dt.Columns.Add(new DataColumn("checkInTime", typeof(string)));
dt.Columns.Add(new DataColumn("outStock", typeof(string)));
DataRow dr = dt.NewRow();
for (int i = 0; i < 20; i++)
{
dt.Rows.Add(new string[] { ("京创" + i).ToString(), (i + 10).ToString(), ("日照"+i).ToString(),
("山东" +i).ToString(),"卷钢" + i.ToString(),(10+i).ToString(),("2019-8-1"+i).ToString(), (i+"号").ToString()});
}
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "DataSet2";
reportDataSource.Value = dt;
rvDoc.reportViewer1.LocalReport.DataSources.Add(reportDataSource);
RDLCPrinter.BillPrint.Run(rvDoc.reportViewer1.LocalReport);
}
}
}
5.运行预览
准备工作结束之后
开始运行
点击打印预览
点击直接打印就直接打印了
上图
手机像素比较差
然后是项目下载地址
链接:https://pan.baidu.com/s/15p_qbIlgP5FQslTSYtqoSA
提取码:9xfp
6.注意点
1.打印预览如果正常,但是打印出来多余空白页的话
如下设置
点击到rdlc文件,然后右边的属性,选择报表
然后把下面的ConsumeContainerWhite设置为true