如何在不显示窗体的情况下打印Windows表单

4

我试图自动打印一系列Windows窗体。我不需要显示它们。我在互联网上找到的代码示例只有在使用show()时才有效!我需要用数据初始化表单并将其发送到打印机。这是我正在使用的代码:

public partial class Form2_withoutShow : Form{

     PrintDocument PrintDoc;

     Bitmap memImage;

     public Form2_withoutShow (Data data)
     {

        InitializeComponent();

        /*
           Initialize Data (texboxes, charts ect.) here
       */

        this.PrintDoc = new PrintDocument();
        this.PrintDoc.PrintPage += PrintDoc_PrintPage;
        this.PrintDoc.DefaultPageSettings.Landscape = true;
     }


     public void Print()
     {
        this.PrintDoc.Print();
     }

     void PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
     {

        int x = SystemInformation.WorkingArea.X;
        int y = SystemInformation.WorkingArea.Y;
        int width = this.Width;
        int height = this.Height; 

        Rectangle bounds = new Rectangle(x, y, width, height);

        Bitmap img = new Bitmap(width, height); 

        this.DrawToBitmap(img, bounds);
        Point p = new Point(10, 10);

        e.Graphics.DrawImage(img, p);
     }

     private void Form2_withoutShow_Load(object sender, EventArgs e)
     {
         // remove TITLEBar
         this.ControlBox = false;
         this.Text = String.Empty;
     }
}

我在另一个类的for循环中调用Print()方法,并通过构造函数传递要初始化的数据。

MSDN示例捕获了应该显示表单部分的屏幕内容。但这对我没有用。现在我正在使用的方法只会打印空窗口,如果不调用show()方法。如何将数据传递到表单中而不必调用show()方法?例如在显示时最小化窗口的方法也不起作用,因为那也是打印结果:一个最小化的窗口。


你解决了吗? - eracube
不,我的目的是打印协议,我认为可以使用填充数据的GUI来完成这个任务。最终我使用MigraDocs创建了一个PDF并将其发送到打印机... - Mong Zhu
@ErAcube,这里有一个答案。你看过了吗? - Mong Zhu
是的,谢谢你指出。我刚刚注意到了。 - eracube
1个回答

8
在显示表单之前,表单及其控件处于Created状态之外。要强制创建表单及其控件,只需调用表单的内部CreateControl(bool fIgnoreVisible)方法即可:
var f = new Form1();
var createControl = f.GetType().GetMethod("CreateControl",
                BindingFlags.Instance | BindingFlags.NonPublic);
createControl.Invoke(f, new object[] { true });

var bm = new Bitmap(f.Width, f.Height);
f.DrawToBitmap(bm, new Rectangle(0, 0, bm.Width, bm.Height));
bm.Save(@"d:\bm.bmp");

同时,移除表单Load事件处理程序中的代码,并将它们放置在表单的构造函数中。

注意

还有其他解决方法:

  • 例如,您可以将窗体显示在屏幕边界外的位置,然后再隐藏它。将Location设置为(-32000, -32000),将StartPosition设置为Manual,然后在绘制位图之前ShowHide窗体。
  • 或者,您可以将窗体的Opacity设置为0,然后在绘制位图之前ShowHide窗体,作为另一个示例。

通常使用报告工具,如RDLC报告,是更好的选择,比如您使用PDF工具所做的,但报告更加友好。无论如何,为了学习目的或在必须通过打印表单完成任务的情况下,我分享了一些可行的选项。首选是第一种选项。 - Reza Aghaei
非常感谢您提供的详细答案。您能否解释一下为什么 createControl 方法必须以 invoke 开头,如果我只是调用 this.CreateControl(),它为什么不起作用? - Mong Zhu
不客气 :) 你需要的重载是 CreateControl(bool fIgnoreVisible),它是内部的,所以即使你想在该窗体的构造函数中调用它,也无法这样做。因此,使用 Reflection 调用该方法是唯一的方法。 - Reza Aghaei
我创建了一个打印方法并在那里调用它。使用您的反射方法,它可以正常工作。我将尝试使用重载方法。 - Mong Zhu
你不能在没有反射的情况下使用该重载。正如答案中所提到的,该重载是内部的。你按照答案中的方式做是正确的。你不需要改变任何东西。 - Reza Aghaei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接