So I have an Window which I want to Print. For that I created an Print Dialog. Which looks like that:
PrinterSettings settings = new PrinterSettings();
string Printer = settings.PrinterName;
System.Windows.Controls.PrintDialog printDlg = new System.Windows.Controls.PrintDialog();
printDlg.PrintQueue = new PrintQueue(new PrintServer(), Printer);
printDlg.PrintTicket.CopyCount = 1;
printDlg.PrintTicket.PageOrientation = PageOrientation.Landscape;
printDlg.PrintVisual(this, "Window Printing.");
But for some reason it opens instant an Dialog for save that Programm as PDF. But I want directly print it to my Printer, without that Dialog. So why does it not Print to my Printer? And how Can I get this to work.
Are you sure you have chosen the correct printer? Because the PrintDialog will behave like this if its printer is set to a file printer, for example to: "Microsoft Print to PDF". (Then, obviously, you have to provide the name of the file the printer should print to, hence the "save" dialog.)
Check what printers you have installed (or rather, what PrintQueues you have available):
LocalPrintServer myPrintServer = new LocalPrintServer();
foreach (PrintQueue pq in myPrintServer.GetPrintQueues())
{
Console.WriteLine(pq.Name);
}
Are you sure you're setting one of those? Which one is the default in your system? Is it maybe a file printer?
Try setting a printer name to the correct, physical printer in code, and check if anything will print:
string myPrinterName = "My Printer"; // <= put an existing name here
LocalPrintServer myPrintServer = new LocalPrintServer();
PrintDialog printDlg = new PrintDialog();
PrintQueue printQueue = myPrintServer.GetPrintQueue(myPrinterName);
printDlg.PrintQueue = printQueue;
printDlg.PrintTicket.CopyCount = 1;
printDlg.PrintTicket.PageOrientation = PageOrientation.Landscape;
printDlg.PrintVisual(this, "Window Printing.");
In the system, is the printer configured correctly?
Related
I'm currently working on a printing application. This app has the requirement that certain pages need to come from specific trays on the printer. Here's the guts of what I've got so far:
foreach (var dto in dispensersToPrint)
{
var documents = FilterDocumentSections(DispenserDocumentsToPrint.RetrieveByDispenserId(dto.DispenserId));
var groupedDocs = documents.GroupBy(t => t.DocumentTypeId);
var queueName = Properties.Settings.Default.PrinterName;
var queue = RawPrinterHelper.GetPrintQueue(queueName);
var seq = new FixedDocumentSequence();
var xpsWriter = PrintQueue.CreateXpsDocumentWriter(queue);
foreach (var docGroup in groupedDocs)
{
var printTicket = queue.DefaultPrintTicket.Clone();
var printTray = MapPrintTray((DocumentSectionType)docGroup.Key);
if (!printTray.IsNullOrEmpty())
{
printTicket = RawPrinterHelper.ModifyPrintTicket(printTicket, "psk:JobInputBin", printTray);
}
var fixedDoc = new FixedDocument();
fixedDoc.PrintTicket = printTicket;
foreach (var doc in docGroup)
{
var pageContent = new PageContent();
var fixedPage = new FixedPage();
var localFileName = string.Empty;
var unzippedFileName = string.Empty;
//copy files locally
localFileName = CopyFileToLocalMachine(doc.FileName);
//unzip file
unzippedFileName = EmfPrintingHelper.UnzipEmfFile(localFileName);
var itemToPrint = new PrintableEmfImage
{
DataContext = new EmfImageViewModel { FileName = unzippedFileName }
};
fixedPage.Children.Add(itemToPrint);
pageContent.Child = fixedPage;
fixedDoc.Pages.Add(pageContent);
}
var docRef = new DocumentReference();
docRef.SetDocument(fixedDoc);
seq.References.Add(docRef);
}
xpsWriter.Write(seq);
}
At a real high level:
For each Dispenser (Work Order) i need to print; i first start by grouping by the DocumentType (i.e. Print type A to tray 1)
I then create a new FixedDocumentSequence
For each DocumentType; I then create a fixed document. I then modify the print ticket to look at the appropriate tray.
I then build each individual page for each document type; and add them to the FixedDocument
Once the building of the FixedDocument is complete; I append it to the DocumentSequence.
I then send the FixedDocumentSequence to the xpsWriter.
But for some reason; these settings aren't being honored. I get all the documents printing out of the same tray.
Here are some of my observations so far:
The modifying of the print ticket does work; I've verified this by sending a modified printTicket into the xpsWriter; but this applies the settings to the entire job; which is a no go for me.
When querying my print capabilities; i noticed that i only have JobInputBin. I don't quite think this means this printer doesn't support the functionality; as multi-tray printing works from a similar WindowsForms app (which uses PageSettings.PaperSource)
Any ideas on what I could try next? Has anyone been successful doing something like this before?
I'll start off by saying, I don't have access to a printer with trays, so I am unfortunately not capable of testing this solution. That said, I'll direct your attention to an MSDN forum post, here, where the original poster was in pursuit of the same tray-per-page behavior.
Based on your posted code, you may have already seen some of what's in this post, judging by your posted code having at least some implementation of ModifyPrintTicket().
In the post, there are several different users, each citing a solution for their specific version of the problem. However, the one that seems most relevant in this case is the solution regarding namespaces not being correctly accounted for in ModifyPrintTicket() (as posted by
Jo0815). I say 'most relevant' because the poster speaks of the print tray being disregarded. They (wittersworld) provide an alternate implementation to correct the issue. In the post on MSDN, the link to the complete source is broken, but can be located here.
The gist is, on ModifyPrintTicket(), they add a namespaceUri parameter, then withing changed this:
if (node != null)
{
node.Attributes["name"].Value = newValue;
}
to this:
if (node != null)
{
if (newValue.StartsWith("ns0000"))
{
// add namespace to xml doc
XmlAttribute namespaceAttribute = xmlDoc.CreateAttribute("xmlns:ns0000");
namespaceAttribute.Value = namespaceUri;
xmlDoc.DocumentElement.Attributes.Append(namespaceAttribute);
}
node.Attributes["name"].Value = newValue;
}
allowing the user to specify the printer-specific namespace used.
I hope this is helpful.
Now I know how to set default printer with printer name by AutomationFactory,
var scriptNetwork = AutomationFactory.CreateObject("WScript.Network");
scriptNetwork.SetDefaultPrinter("Microsoft XPS Document Writer");
after I finish my printing to specified printer, I need to change the default printer back to the original, how can I get the original default printer name??
Thanks.
Try this please,
private string GetDefaultPrinter()
{
var oShell = AutomationFactory.CreateObject("WScript.Shell");
string sRegVal = "HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Device";
string sDefault = "";
sDefault = oShell.RegRead(sRegVal);
sDefault = sDefault.Split(new String[] {","}, StringSplitOptions.None)[0];
return sDefault;
}
Writing my first silverlight application.
I need to deliver some bitmap that the customer will choose ( used OpenFileDialog ) to the server side ( using web service ).
After the customer choosing the bitmap - i cant access the file and break hit to byte array because i dont see the file full path on the OpenFileDialog object properties.
How can i do it ?
( i have method that get Bitmap and return the bitmap as byte array )
I did that before, here is part of it:
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "Images (*.png; *.jpg)| *.png; *.jpg";
dialog.Multiselect = false;
if (dialog.ShowDialog() == true)
{
using (System.IO.Stream stream = dialog.File.OpenRead())
{
BinaryReader binaryReader = new BinaryReader(stream);
// here are the bytes you want, put them somewhere to send them to the server
byte[] imageBytes = binaryReader.ReadBytes((int)stream.Length);
// here is the filename if you need it
string filename = System.IO.Path.GetFileNameWithoutExtension(dialog.File.Name);
stream.Close();
}
}
question 1. I have this issue of "Object reference not set to an instance of an object" when my Majorlabel is empty and this occurs after i try to do a save button click on xml serialization. How can i fix this?
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
string savepath;
SaveFileDialog DialogSave = new SaveFileDialog();
// Default file extension
DialogSave.DefaultExt = "txt";
// Available file extensions
DialogSave.Filter = "XML file (*.xml)|*.xml|All files (*.*)|*.*";
// Adds a extension if the user does not
DialogSave.AddExtension = true;
// Restores the selected directory, next time
DialogSave.RestoreDirectory = true;
// Dialog title
DialogSave.Title = "Where do you want to save the file?";
// Startup directory
DialogSave.InitialDirectory = #"C:/";
DialogSave.ShowDialog();
savepath = DialogSave.FileName;
DialogSave.Dispose();
DialogSave = null;
FormSaving abc = new FormSaving();
if (!string.IsNullOrEmpty(MajorversionresultLabel.Content.ToString()))
{
abc.Majorversion = MajorversionresultLabel.Content.ToString();
}
abc.Startzbuildfrom = StartzbuildcomboBox.SelectedItem.ToString();
using (Stream savestream = new FileStream(savepath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, abc);
}
}
As recommended,
here is the line of error:
if (!string.IsNullOrEmpty(MajorversionresultLabel.Content.ToString()))
{
abc.Majorversion = MajorversionresultLabel.Content.ToString();
}
Question 2. I used this line to save my combo box selection:
abc.Startzbuildfrom = StartzbuildcomboBox.SelectedItem.ToString();
and in my load i have this line:
StartzbuildcomboBox.SelectedItem = abc.Startzbuildfrom
why wont it select the combobox selection previously?
As a first note, I'd recommend only putting one question into a single query here. Makes it easier.
For your second question, my guess is that you're running into a reference variable problem. I think that calling the ToString() method on the SelectedItem actually creates an entirely new string variable. Then, when you try to set the selected item later, it can't find the new string as a possible item to select because, even though the two strings have the same value, they are different objects. I would maybe recommend that you either:
1) Set the selected item by searching through your combo box contents to find a string whose value matches the one you've saved
or
2) Save the actual reference by saying abc.Startzbuildfrom = StartzbuildcomboBox.SelectedItem. Then set the selected item from that reference.
I suspect that MajorversionresultLabel is null, or MajorversionresultLabel.Content is null. Thus your statement
if (!string.IsNullOrEmpty(MajorversionresultLabel.Content.ToString()))
will throw a NullReferenceException. Try this instead:
if (MajorversionresultLabel != null && MajorversionresultLabel.Content != null && MajorversionLabel.Content.ToString() != string.Empty)
I bet your NullReferenceException will go away.
I'm building a demo app in WPF, which is new to me. I'm currently displaying text in a FlowDocument, and need to print it.
The code I'm using looks like this:
PrintDialog pd = new PrintDialog();
fd.PageHeight = pd.PrintableAreaHeight;
fd.PageWidth = pd.PrintableAreaWidth;
fd.PagePadding = new Thickness(50);
fd.ColumnGap = 0;
fd.ColumnWidth = pd.PrintableAreaWidth;
IDocumentPaginatorSource dps = fd;
pd.PrintDocument(dps.DocumentPaginator, "flow doc");
fd is my FlowDocument, and for now I'm using the default printer instead of allowing the user to specify print options. It works OK, except that after the document prints, the FlowDocument displayed on screen has changed to to use the settings I specified for printing.
I can fix this by manually resetting everything after I print, but is this the best way? Should I make a copy of the FlowDocument before I print it? Or is there another approach I should consider?
yes, make a copy of the FlowDocument before printing it. This is because the pagination and margins will be different. This works for me.
private void DoThePrint(System.Windows.Documents.FlowDocument document)
{
// Clone the source document's content into a new FlowDocument.
// This is because the pagination for the printer needs to be
// done differently than the pagination for the displayed page.
// We print the copy, rather that the original FlowDocument.
System.IO.MemoryStream s = new System.IO.MemoryStream();
TextRange source = new TextRange(document.ContentStart, document.ContentEnd);
source.Save(s, DataFormats.Xaml);
FlowDocument copy = new FlowDocument();
TextRange dest = new TextRange(copy.ContentStart, copy.ContentEnd);
dest.Load(s, DataFormats.Xaml);
// Create a XpsDocumentWriter object, implicitly opening a Windows common print dialog,
// and allowing the user to select a printer.
// get information about the dimensions of the seleted printer+media.
System.Printing.PrintDocumentImageableArea ia = null;
System.Windows.Xps.XpsDocumentWriter docWriter = System.Printing.PrintQueue.CreateXpsDocumentWriter(ref ia);
if (docWriter != null && ia != null)
{
DocumentPaginator paginator = ((IDocumentPaginatorSource)copy).DocumentPaginator;
// Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device.
paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight);
Thickness t = new Thickness(72); // copy.PagePadding;
copy.PagePadding = new Thickness(
Math.Max(ia.OriginWidth, t.Left),
Math.Max(ia.OriginHeight, t.Top),
Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), t.Right),
Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), t.Bottom));
copy.ColumnWidth = double.PositiveInfinity;
//copy.PageWidth = 528; // allow the page to be the natural with of the output device
// Send content to the printer.
docWriter.Write(paginator);
}
}
You can use the code from the URL below, it wraps the flow document in a fixed document and prints that, the big advantage is that you can use it to add margin, headers and footers.
https://web.archive.org/web/20150502085246/http://blogs.msdn.com:80/b/fyuan/archive/2007/03/10/convert-xaml-flow-document-to-xps-with-style-multiple-page-page-size-header-margin.aspx
The following works with both text and non-text visuals:
//Clone the source document
var str = XamlWriter.Save(FlowDoc);
var stringReader = new System.IO.StringReader(str);
var xmlReader = XmlReader.Create(stringReader);
var CloneDoc = XamlReader.Load(xmlReader) as FlowDocument;
//Now print using PrintDialog
var pd = new PrintDialog();
if (pd.ShowDialog().Value)
{
CloneDoc.PageHeight = pd.PrintableAreaHeight;
CloneDoc.PageWidth = pd.PrintableAreaWidth;
IDocumentPaginatorSource idocument = CloneDoc as IDocumentPaginatorSource;
pd.PrintDocument(idocument.DocumentPaginator, "Printing FlowDocument");
}
I am also generating a WPF report off a Flow document, but I am purposely using the flow document as a print preview screen. I there for want the margins to be the same. You can read about how I did this here.
In your scenario I'm thinking why not just make a copy of your settings, instead of the entire flow document. You can then re-apply the settings if you wish to return the document back to it's original state.