My project needs to print a simple string object to a printer of choice using something like the WPF System.Windows.Controls.PrintDialog.
I created a standard System.Drawing.Printing.PrintDocument but it does not have a DocumentPaginator that is required for the PrintDocument() method belonging to the PrintDialog class.
This seems like a trivial task to print a string to a printer with a dialog to show printer choices, but is turning out significantly more difficult. Please Help!
Since you're using WPF, instead of using the PrintDocument, just create a FlowDocument. I think that's a lot easier.
var dlg = new PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = false;
if(dlg.ShowDialog() == true)
{
var doc = new FlowDocument();
// For normal A4&/letter pages, the defaults will print in two columns
doc.ColumnWidth = dlg.PrintableAreaWidth;
doc.Blocks.Add(new Paragraph(new Run("My arbitrary long string to print.\nNewlines work. Pages will break as needed.")));
dlg.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator, "Simple document");
}
Related
Using C#, I need to pull data from a word document. I have NetOffice for word installed in the project. The data is in two parts.
First, I need to pull data from the document settings.
Second, I need to pull the content of controls in the document. The content of the fields includes checkboxes, a date, and a few paragraphs. The input method is via controls, so there must be some way to interact with the controls via the api, but I don't know how to do that.
right now, I've got the following code to pull the flat text from the document:
private static string wordDocument2String(string file)
{
NetOffice.WordApi.Application wordApplication = new NetOffice.WordApi.Application();
NetOffice.WordApi.Document newDocument = wordApplication.Documents.Open(file);
string txt = newDocument.Content.Text;
wordApplication.Quit();
wordApplication.Dispose();
return txt;
}
So the question is: how do I pull the data from the controls from the document, and how do I pull the document settings (such as the title, author, etc. as seen from word), using either NetOffice, or some other package?
I did not bother to implement NetOffice, but the commands should mostly be the same (except probably for implementation and disposal methods).
Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
string file = "C:\\Hello World.docx";
Microsoft.Office.Interop.Word.Document doc = word.Documents.Open(file);
// look for a specific type of Field (there are about 200 to choose from).
foreach (Field f in doc.Fields)
{
if (f.Type == WdFieldType.wdFieldDate)
{
//do something
}
}
// example of the myriad properties that could be associated with "document settings"
WdProtectionType protType = doc.ProtectionType;
if (protType.Equals(WdProtectionType.wdAllowOnlyComments))
{
//do something else
}
The MSDN reference on Word Interop is where you will find information on just about anything you need access to in a Word document.
UPDATE:
After reading your comment, here are a few document settings you can access:
string author = doc.BuiltInDocumentProperties("Author").Value;
string name = doc.Name; // this gives you the file name.
// not clear what you mean by "title"
As far as trying to understand what text you are getting from a "legacy control", I need more information as to exactly what kind of control you are extracting from. Try getting a name of the control/textbox/form/etc from within the document itself and then look up that property on the Google.
As a stab in the dark, here is an (incomplete) example of getting text from textboxes in the document:
List<string> textBoxText = new List<string>();
foreach (Microsoft.Office.Interop.Word.Shape s in doc.Shapes)
{
textBoxText.Add(s.TextFrame.TextRange.Text); //this could result in an error if there are shapes that don't contain text.
}
Another possibility is Content Controls, of which there are several types. They are often used to gather user input.
Here is some code to catch a rich text Content Control:
List<string> contentControlText = new List<string>();
foreach(ContentControl CC in doc.ContentControls)
{
if (CC.Type == WdContentControlType.wdContentControlRichText)
{
contentControlText.Add(CC.Range.Text);
}
}
I've seen many posts with regards to setting printer tray in c# for word document. I need a solution for Excel.
A better solution, if possible, for any document. Some kind of method i can pass a file path and the tray.
EDIT
So far I've tried the following but no visible changes have been made in the printer settings.
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = #"\\localhost\HP-4515n";
var dps = ps.DefaultPageSettings;
dps.PaperSource.RawKind = 260;
OR
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = #"\\localhost\HP-4515n";
PaperSource psrc = new PaperSource();
psrc.RawKind = 260;
psrc.SourceName = "unknown";
dps.PaperSource = psrc;
EDIT 2
I'm hardcoding RawKind since the tray somehow does not show in the papersources.
And currently when i print eg. Excel document i show the PrinterDialog, get the name of the selected printer and pass it to interop Excel active printer property. But now i need to print mass of documents and i need to set the selected printer and it's property specially the tray programmatically.
#sysboard, I see from the MSDN page on the PrinterSettings class that the DefaultPageSettings property does not have a set method, only a get method. I am not sure that this is accessible from external classes...You might look into the PageSettings class as it looks like it has an overloaded constructor that allows you to pass a specified printer, and it has a set method on PaperSource.
You can get the available papersources using the folowing code :
PrintDocument printDoc1 = new PrintDocument();
List<PaperSource> psList = new List<PaperSource>();
PaperSource pkSource;
for (int i = 0; i < printDoc1.PrinterSettings.PaperSources.Count; i++)
{
pkSource = printDoc1.PrinterSettings.PaperSources[i];
psList.Add(pkSource);
}
Now present these options to the user and get the input as to which paper source to use, say its the first one, you can do :
PrintDocument doc = new PrintDocument();
doc.DefaultPageSettings.PaperSource = psList[0];
doc.Print();
Why you are hardcoding psrc.RawKind = 260;
To set a RawKind for a Paper Source there is PaperSourceKind enum available. try the following code
PrintDocument doc = new PrintDocument();
PaperSource pSource = new PaperSource();
pSource.RawKind = (int)PaperSourceKind.Middle;
doc.DefaultPageSettings.PaperSource = pSource;
I'm trying to print labels with a dynamic content. The print works fine but the problem is that the printing itself (the font) is 90 degrees twisted. It looks like this:
But it should look like this:
I cannot change the settings of the printer because other labels do print correct. So I think it must be something in the code. You can watch the C# code here:
System.Drawing.Printing.PrinterSettings printerSettings = new System.Drawing.Printing.PrinterSettings();
printerSettings.PrinterName = #"\\server\printer";
printerSettings.Copies = Convert.ToInt16((Convert.ToInt16(row.Cells["Counter"].Value.ToString()) - 1));
System.Drawing.Printing.PrintController standardPrintController = new System.Drawing.Printing.StandardPrintController();
Telerik.Reporting.Processing.ReportProcessor reportProcessor = new Telerik.Reporting.Processing.ReportProcessor();
reportProcessor.PrintController = standardPrintController;
Telerik.Reporting.InstanceReportSource instanceReportSource = new Telerik.Reporting.InstanceReportSource();
instanceReportSource.ReportDocument = myReport;
reportProcessor.PrintReport(instanceReportSource, printerSettings);
Does anyone know such a problem or a possible solution?
Suggestion very appreciated :)
I've had the same problem once, but never used Telerik for anything. I was trying to print a XPS file with the PrintServer object, and came up with this solution to rotate the print.
Basicly I change the page orientation of the queue before I print for the user, and then change it back afterwards.
It might be usefull to you as well.
PrintServer ps = new PrintServer("\\\\somePrintServer");
var queue = ps.GetPrintQueue("printerShareName");
var oldOrientation = queue.UserPrintTicket.PageOrientation;
queue.UserPrintTicket.PageOrientation = PageOrientation.Landscape;
//print job here
queue.UserPrintTicket.PageOrientation = oldOrientation;
Is there a way to switch printer trays during a print job? I've been asked to put together a pick/pack slip program. They want the inventory pick slip to be printed on a sheet of colored paper, the pack slips to be on white paper, and they want it properly collated (pick, pack, pack, pack, pack; pick, pack, pack, pack, pack; ...).
I found some other threads on setting default trays, but didn't find anything on alternating trays during the job. Maybe I'm not searching on the right thing.
Don't know if it makes a difference, but our printer is an HP 3015n and the clients will be both XP and Win 7 Pro.
You can try something like this you have to reference System.Drawing.dll from the projects --> Reference--> Add
//Namespace: System.Drawing.Printing
//Assembly: System.Drawing (in System.Drawing.dll)
PrintDocument printDoc = new PrintDocument();
PaperSize oPS = new PaperSize();
oPS.RawKind = (int)PaperKind.A4;
PaperSource oPSource = new PaperSource();
oPSource.RawKind = (int) PaperSourceKind.Upper;
printDoc.PrinterSettings = new PrinterSettings();
printDoc.PrinterSettings.PrinterName = sPrinterName;
printDoc.DefaultPageSettings.PaperSize = oPS;
printDoc.DefaultPageSettings.PaperSource = oPSource;
printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
printDoc.Print();
printDoc.Dispose();
To my knowledge no - you have to submit 2 jobs on a queue that basically only you use.
You can change printer tray with this code.
string _paperSource = "TRAY 2"; // Printer Tray
string _paperName = "8x17"; // Printer paper name
//Tested code comment. The commented code was the one I tested, but when
//I was writing the post I realized that could be done with less code.
//PaperSize pSize = new PaperSize() //Tested code :)
//PaperSource pSource = new PaperSource(); //Tested code :)
/// Find selected paperSource and paperName.
foreach (PaperSource _pSource in printDoc.PrinterSettings.PaperSources)
{
if (_pSource.SourceName.ToUpper() == _paperSource.ToUpper())
{
printDoc.DefaultPageSettings.PaperSource = _pSource;
//pSource = _pSource; //Tested code :)
break;
}
}
foreach (PaperSize _pSize in printDoc.PrinterSettings.PaperSizes)
{
if (_pSize.PaperName.ToUpper() == _paperName.ToUpper())
{
printDoc.DefaultPageSettings.PaperSize = _pSize;
//pSize = _pSize; //Tested code :)
break;
}
}
//printDoc.DefaultPageSettings.PaperSize = pSize; //Tested code :)
//printDoc.DefaultPageSettings.PaperSource = pSource; //Tested code :)
I'm having some trouble reading the contents of a Datagrid in an external application using UI Automation and could use some pointers. Here's what I have so far:
int id = System.Diagnostics.Process.GetProcessesByName("Book")[0].Id;
AutomationElement desktop = AutomationElement.RootElement;
AutomationElement bw = desktop.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ProcessIdProperty, id));
AutomationElement datagrid = bw.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "lv"));
AutomationElementCollection lines = datagrid.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataItem));
AutomationElementCollection items = lines[1].FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom));
GridItemPattern pattern = items[1].GetCurrentPattern(GridItemPattern.Pattern) as GridItemPattern;
TableItemPattern tablePattern = items[1].GetCurrentPattern(TableItemPattern.Pattern) as TableItemPattern;
This works in as much as I can access the column ids and row ids from the GridItemPattern and TableItemPattern but how do I access the value that is in that specific cell? Is it even possible?
Thanks.
I think you need to use ValuePattern for it. Just like that:
ValuePattern pattern = items[0].GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
string value = pattern.Current.Value;
I finally figured this out, it requires the use of CacheRequest to request the Name property on the AutomationElement. Here's the final code:
var cacheRequest = new CacheRequest
{
AutomationElementMode = AutomationElementMode.None,
TreeFilter = Automation.RawViewCondition
};
cacheRequest.Add(AutomationElement.NameProperty);
cacheRequest.Add(AutomationElement.AutomationIdProperty);
cacheRequest.Push();
var targetText = loginLinesDetails[i].FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "TextBlock"));
cacheRequest.Pop();
var myString = targetText.Cached.Name;
I am not familiar with the AutomationElement classes but I have used AutoIT to automate some simple windows stuff in the past (find a dialog, click a button, etc) and it was cake. You might consider it. The download contains a .dll you can reference from a .Net solution.
I'm not sure if the external app is a WinForm grid or not but here is an ASP.Net grid example: http://www.autoitscript.com/forum/topic/13709-how-to-get-the-contents-of-datagrid-control/
Then again, if you are scraping the info from the web I would recommend WatiN or Selenium
You can try using RawViewWalker on a element to get raw values (On controlview you might not be able to get few properties)