2017-02-22 3 views
0

Ich habe ein C# WPF .NET 4.6 Programm, das HTML-Dateien erstellt und ich möchte sie automatisch (ohne Dialog) mit einem bekannten, nicht standardmäßigen Drucker drucken. Natürlich beinhaltet dies das Rendern des HTML-Codes. Da das Programm diese Dateien erstellt, können die HTML-Daten aus einer MemoryStream, FileStream oder direkt aus einer Zeichenfolge stammen.Rendern und Drucken von HTML zu nicht standardmäßigen Drucker

Das Programm verfügt über Einstellungen, mit denen der Benutzer im Voraus unter Verwendung von System.Drawing.Printing.PrinterSettings.InstalledPrinters angeben kann, auf welchem ​​Drucker gedruckt werden soll, da für jede Datei möglicherweise ein anderer Drucker erforderlich ist. Zur Druckzeit ist der Name des Druckers bekannt, wird sich aber wahrscheinlich vom Windows-Standarddrucker unterscheiden.

Ich habe viele andere Projekte recherchiert, aber sie scheinen nicht zu erklären, dass der Drucker vom Standard abweicht. Das Ändern des Standarddruckers wäre antisozial und würde eine Welt von Threading-bedingten Schmerzen verursachen. Dies scheint die # 1 akzeptierte Lösung zu sein, obwohl sie nicht die beste Lösung sein kann.


Forschung und Lösungen sah:

Printing the contents of a WPF WebBrowser und Silently print HTML from WPF WebBrowser und corresponding MSDNforum discussions unzureichend sind als COM ExecWB Funktion druckt nur auf dem Standarddrucker

Die MSDN example nur verwendet das (?) Print() Befehl auf dem WebBrowser, der wieder den Standarddrucker verwendet.

Also ging ich den Weg des Versuchs, die Druckeroptionen zu ändern. Programmatically changing the destination printer for a WinForms WebBrowser control wurde gefragt, hat aber eine eher unbefriedigende Antwort, da es einen defekten Link hat, und ich weiß nicht, welche externen Programme der running Computer hat, also kann ich nicht garantieren, dass Adobe, OpenOffice, etc. OP das ActiveX COM analysiert haben ohne ins Detail zu gehen. Klingt knifflig.

Vielleicht könnte ich etwas vom Schreiben auf eine RichTextBox glänzen wie this project tut, und verstecken Sie die Box?

Ich dachte, Silent print HTML file in C# using WPF ist auf einem guten Weg, aber die ursprüngliche Post hat fest codierte Zahlen für Bildschirmabmessungen‽ und OP erwähnt, dass der Drucker das Dokument abgeschnitten. Die angenommene (und gebootete) Antwort verwenden Sie erneut die ExecWB Standard-Druckereinstellungen Methode.

execCommand("Print", false, IDon'tUnderstandThisArgument) zeigte auch Versprechen, als Antwort eine aktualisierte MSDN answer war, aber die Filestream an den Drucker nicht erlauben HTML gesendet, noch hat die DocumentStream von WebBrowser erscheinen (der Drucker eine einzelne leere Seite druckt) zu arbeiten.

How do I programatically change printer settings with the WebBrowser control? hat sehr ähnliche Anforderungen an mich, außer ändert die Registrierung als eine Lösung.

Andere als die Erforschung, wie andere es getan haben, ich habe auch versucht, die WPF Druck WebBrowser direkt, da es eine Visual Kontrolle: (weil die WebBrowser nicht sichtbar ist)

public static bool Print(string printer, Visual objToPrint) 
    { 
     if (string.IsNullOrEmpty(printer)) 
     { 
     return false; 
     } 

     var dlg = new PrintDialog 
     { 
     PrintQueue = new PrintServer().GetPrintQueue(printer) 
     }; 

     dlg.PrintTicket.CopyCount = 1; 
     dlg.PrintTicket.PageOrientation = PageOrientation.Portrait; 
     dlg.PrintTicket.PagesPerSheet = 1; 

     dlg.PrintVisual(objToPrint, "Print description"); 
     return true; 
    } 

aber dies alles nicht gedruckt .Und versuchte ein PrintDocument wie die aktualisierte MSDN article vorgeschlagen:

public static async Task<bool> PrintHTMLAsync(string printer, string html) 
    { 
     bool result; 
     using (var webBrowser = new System.Windows.Forms.WebBrowser()) 
     { 
     webBrowser.DocumentCompleted += ((sender, e) => browserReadySemaphore.Release()); 
     byte[] buffer = Encoding.UTF8.GetBytes(html); 
     webBrowser.DocumentStream = new MemoryStream(buffer); 

     // Wait until the page loads. 
     await browserReadySemaphore.WaitAsync(); 

     try 
     { 
      using (PrintDocument pd = new PrintDocument()) 
      { 
      pd.PrinterSettings.PrinterName = printer; 
      pd.PrinterSettings.Collate = false; 
      pd.PrinterSettings.Copies = 1; 
      pd.PrinterSettings.FromPage = 1; 
      pd.PrinterSettings.ToPage = 1; 
      pd.Print(); 
      result = true; 
      } 
     } 
     catch (Exception ex) 
     { 
      result = false; 
      Debug.WriteLine(ex); 
     } 

     return result; 
     } 
    } 

ohne Freude.

Ich habe auch den PRINT-DOS-Befehl:

public static string PerformSilentPrinting(string fileName, string printerName) 
{ 
    try 
    { 
    ProcessStartInfo startInfo = new ProcessStartInfo(fileName) 
    { 
     Arguments = string.Format("/C PRINT /D:\"{0}\" \"{1}\"", printerName, fileName), 
     FileName = "cmd.exe", 
     RedirectStandardOutput = true, 
     UseShellExecute = false, 
     WindowStyle = ProcessWindowStyle.Hidden, 
    }; 

    // Will execute the batch file with the provided arguments 
    Process process = Process.Start(startInfo); 

    // Reads the output   
    return process.StandardOutput.ReadToEnd(); 
    } 
    catch (Exception ex) 
    { 
    return ex.ToString(); 
    } 
} 

aber der Druckbefehl scheint nur, um Textdateien zu akzeptieren.

Antwort

0

EDIT: Diese Lösung funktioniert gut, wenn Sie nur eine A4-Seite drucken müssen. Es wird jedoch nur eine Seite gedruckt und alles darüber abgeschnitten.


Am Ende habe ich mit einem WinForms WebBrowser ging, kopiert die Steuerung in eine Bitmap, und gedruckte PrintDialog verwenden, die auch im System.Windows.Forms Namespace ist.

using Microsoft.Win32; 
using System; 
using System.ComponentModel; 
using System.Drawing; 
using System.Drawing.Printing; 
using System.IO; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

public static class PrintUtility 
{ 
    private static readonly SemaphoreSlim browserReadySemaphore = new SemaphoreSlim(0); 

    // A4 dimensions. 
    private const int DPI = 600; 
    private const int WIDTH = (int)(8.3 * DPI); 
    private const int HEIGHT = (int)(11.7 * DPI); 

    public static void Print(this Image image, string printer, bool showDialog = false) 
    { 
    if (printer == null) 
    { 
     throw new ArgumentNullException("Printer cannot be null.", nameof(printer)); 
    } 

    using (PrintDialog printDialog = new PrintDialog()) 
    { 
     using (PrintDocument printDoc = new PrintDocument()) 
     { 
     printDialog.Document = printDoc; 
     printDialog.Document.DocumentName = "My Document"; 
     printDialog.Document.OriginAtMargins = false; 
     printDialog.PrinterSettings.PrinterName = printer; 

     printDoc.PrintPage += (sender, e) => 
     { 
      // Draw to fill page 
      e.Graphics.DrawImage(image, 0, 0, e.PageSettings.PrintableArea.Width, e.PageSettings.PrintableArea.Height); 

      // Draw to default margins 
      // e.Graphics.DrawImage(image, e.MarginBounds); 
     }; 

     bool doPrint = !showDialog; 
     if (showDialog) 
     { 
      var result = printDialog.ShowDialog(); 
      doPrint = (result == DialogResult.OK); 
     } 

     if (doPrint) 
     { 
      printDoc.Print(); 
     } 
     } 
    } 
    } 

    public static async Task<bool> RenderAndPrintHTMLAsync(string html, string printer) 
    { 
    bool result = false; 

    // Enable HTML5 etc. (assuming we're running IE9+) 
    SetFeatureBrowserFeature("FEATURE_BROWSER_EMULATION", 9000); 

    // Force software rendering 
    SetFeatureBrowserFeature("FEATURE_IVIEWOBJECTDRAW_DMLT9_WITH_GDI", 1); 
    SetFeatureBrowserFeature("FEATURE_GPU_RENDERING", 0); 

    using (var webBrowser = new WebBrowser()) 
    { 
     webBrowser.ScrollBarsEnabled = false; 
     webBrowser.Width = WIDTH; 
     webBrowser.Height = HEIGHT; 
     webBrowser.DocumentCompleted += ((s, e) => browserReadySemaphore.Release()); 
     webBrowser.LoadHTML(html); 

     // Wait until the page loads. 
     await browserReadySemaphore.WaitAsync(); 

     // Save the picture 
     using (var bitmap = webBrowser.ToBitmap()) 
     { 
     bitmap.Save("WebBrowser_Bitmap.bmp"); 
     Print(bitmap, printer); 
     result = true; 
     } 
    } 

    return result; 
    } 

    /// <summary> 
    /// Make a Bitmap from the Control. 
    /// Remember to dispose after. 
    /// </summary> 
    /// <param name="control"></param> 
    /// <returns></returns> 
    public static Bitmap ToBitmap(this Control control) 
    { 
    Bitmap bitmap = new Bitmap(control.Width, control.Height); 
    Rectangle rect = new Rectangle(0, 0, control.Width, control.Height); 
    control.DrawToBitmap(bitmap, new Rectangle(0, 0, control.Width, control.Height)); 
    return bitmap; 
    } 

    /// <summary> 
    /// Required because of a bug where the WebBrowser only loads text once or not at all. 
    /// </summary> 
    /// <param name="webBrowser"></param> 
    /// <param name="htmlToLoad"></param> 
    /// <remarks> 
    /// http://stackoverflow.com/questions/5362591/how-to-display-the-string-html-contents-into-webbrowser-control/23736063#23736063 
    /// </remarks> 
    public static void LoadHTML(this WebBrowser webBrowser, string htmlToLoad) 
    { 
    webBrowser.Document.OpenNew(true); 
    webBrowser.Document.Write(htmlToLoad); 
    webBrowser.Refresh(); 
    } 

    /// <summary> 
    /// WebBrowser Feature Control 
    /// </summary> 
    /// <param name="feature"></param> 
    /// <param name="value"></param> 
    /// <remarks> 
    /// http://stackoverflow.com/questions/21697048/how-to-fix-a-opacity-bug-with-drawtobitmap-on-webbrowser-control/21828265#21828265 
    /// http://msdn.microsoft.com/en-us/library/ie/ee330733(v=vs.85).aspx 
    /// </remarks> 
    private static void SetFeatureBrowserFeature(string feature, uint value) 
    { 
    if (LicenseManager.UsageMode != LicenseUsageMode.Runtime) 
    { 
     return; 
    } 

    var appName = Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); 
    Registry.SetValue(
     @"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\" + feature, 
     appName, 
     value, 
     RegistryValueKind.DWord); 
    } 
}