我正在尝试将TextBox
我的 XAML 页面上的内容打印到打印机。
我在这条线上遇到了一个例外:
PrintingRoot.Children.Add(firstPage);
对于上面的行,它说“对象引用未设置为对象的实例。”。但我不确定为什么,因为我正在向它添加一个页面。
该行所在的方法是:
public void PreparetPrintContent()
{
if (firstPage == null)
{
firstPage = new MainPage();
}
PrintingRoot.Children.Add(firstPage);
PrintingRoot.InvalidateMeasure();
PrintingRoot.UpdateLayout();
}
我究竟做错了什么?我怎样才能把我的 TextBox 的内容打印到打印机上?
完整代码:
private async void Print_Click_1(object sender, RoutedEventArgs e)
{
MainPage pg = FindVisualParent<MainPage>(this);
IList<Frame> fl = FindVisualChildList<Frame>(pg);
//TextBox to = FindVisualChild<TextBox>(fl[0], "textContent");
TextBox tp = FindVisualChild<TextBox>(firstPage, "textContent");
//tp.Text = to.Text;
// Don't act when in snapped mode
if (ApplicationView.Value != ApplicationViewState.Snapped)
{
await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync();
}
}
private static IList<childItemType> FindVisualChildList<childItemType>(DependencyObject obj) where childItemType : DependencyObject
{
IList<childItemType> list;
list = new List<childItemType>();
FindVisualChildList<childItemType>(obj, list);
return list;
}
private static void FindVisualChildList<childItemType>(DependencyObject obj, IList<childItemType> list) where childItemType : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItemType)
list.Add((childItemType)child);
else
FindVisualChildList<childItemType>(child, list);
}
return;
}
private static childItemType FindVisualChild<childItemType>(DependencyObject obj, string name) where childItemType : FrameworkElement
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is childItemType && ((FrameworkElement)child).Name == name)
return (childItemType)child;
else
{
childItemType childOfChild = FindVisualChild<childItemType>(child, name);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
private static parentItemType FindVisualParent<parentItemType>(DependencyObject o) where parentItemType : FrameworkElement
{
if (o == null)
return null;
if ((o is parentItemType))
return o as parentItemType;
return FindVisualParent<parentItemType>(VisualTreeHelper.GetParent(o));
}
public void PreparetPrintContent()
{
if (firstPage == null)
{
firstPage = new MainPage();
}
PrintingRoot.Children.Add(firstPage);
PrintingRoot.InvalidateMeasure();
PrintingRoot.UpdateLayout();
}
private async void InvokePrintButtonClick(object sender, RoutedEventArgs e)
{
MainPage pg = FindVisualParent<MainPage>(this);
IList<Frame> fl = FindVisualChildList<Frame>(pg);
TextBox to = FindVisualChild<TextBox>(fl[2], "textContent");
TextBox tp = FindVisualChild<TextBox>(firstPage, "textContent");
tp.Text = to.Text;
// Don't act when in snapped mode
if (ApplicationView.Value != ApplicationViewState.Snapped)
{
await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync();
}
}
#region Application Content Size Constants given in percents ( normalized )
/// <summary>
/// The percent of app's margin width, content is set at 85% (0.85) of the area's width
/// </summary>
protected const double ApplicationContentMarginLeft = 0.075;
/// <summary>
/// The percent of app's margin height, content is set at 94% (0.94) of tha area's height
/// </summary>
protected const double ApplicationContentMarginTop = 0.03;
#endregion
/// <summary>
/// A pointer back to the main page which is used to gain access to the input and output frames and their content.
/// </summary>
protected MainPage rootPage = null;
/// <summary>
/// PrintDocument is used to prepare the pages for printing.
/// Prepare the pages to print in the handlers for the Paginate, GetPreviewPage, and AddPages events.
/// </summary>
protected PrintDocument printDocument = null;
/// <summary>
/// Marker interface for document source
/// </summary>
protected IPrintDocumentSource printDocumentSource = null;
/// <summary>
/// A list of UIElements used to store the print preview pages. This gives easy access
/// to any desired preview page.
/// </summary>
internal List<UIElement> printPreviewPages = null;
/// <summary>
/// First page in the printing-content series
/// From this "virtual sized" paged content is split(text is flowing) to "printing pages"
/// </summary>
protected FrameworkElement firstPage;
/// <summary>
/// Factory method for every scenario that will create/generate print content specific to each scenario
/// For scenarios 1-5: it will create the first page from which content will flow
/// Scenario 6 uses a different approach
/// </summary>
//protected virtual void PreparetPrintContent() {}
public void BasePrintPage()
{
printPreviewPages = new List<UIElement>();
}
/// <summary>
/// Printing root property on each input page.
/// </summary>
protected virtual Canvas PrintingRoot
{
get
{
return FindName("printingRoot") as Canvas;
}
}
/// <summary>
/// This is the event handler for PrintManager.PrintTaskRequested.
/// </summary>
/// <param name="sender">PrintManager</param>
/// <param name="e">PrintTaskRequestedEventArgs </param>
protected virtual void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e)
{
PrintTask printTask = null;
printTask = e.Request.CreatePrintTask("C# Printing SDK Sample", sourceRequested =>
{
// Print Task event handler is invoked when the print job is completed.
printTask.Completed += async (s, args) =>
{
// Notify the user when the print operation fails.
if (args.Completion == PrintTaskCompletion.Failed)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
//rootPage.NotifyUser("Failed to print.", NotifyType.ErrorMessage);
});
}
};
sourceRequested.SetSource(printDocumentSource);
});
}
/// <summary>
/// This function registers the app for printing with Windows and sets up the necessary event handlers for the print process.
/// </summary>
protected void RegisterForPrinting()
{
// Create the PrintDocument.
printDocument = new PrintDocument();
// Save the DocumentSource.
printDocumentSource = printDocument.DocumentSource;
// Add an event handler which creates preview pages.
printDocument.Paginate += CreatePrintPreviewPages;
// Add an event handler which provides a specified preview page.
printDocument.GetPreviewPage += GetPrintPreviewPage;
// Add an event handler which provides all final print pages.
printDocument.AddPages += AddPrintPages;
// Create a PrintManager and add a handler for printing initialization.
PrintManager printMan = PrintManager.GetForCurrentView();
printMan.PrintTaskRequested += PrintTaskRequested;
// Initialize print content for this scenario
PreparetPrintContent();
}
/// <summary>
/// This function unregisters the app for printing with Windows.
/// </summary>
protected virtual void UnregisterForPrinting()
{
if (printDocument == null)
return;
printDocument.Paginate -= CreatePrintPreviewPages;
printDocument.GetPreviewPage -= GetPrintPreviewPage;
printDocument.AddPages -= AddPrintPages;
// Remove the handler for printing initialization.
PrintManager printMan = PrintManager.GetForCurrentView();
printMan.PrintTaskRequested -= PrintTaskRequested;
PrintingRoot.Children.Clear();
}
protected event EventHandler pagesCreated;
/// <summary>
/// This is the event handler for PrintDocument.Paginate. It creates print preview pages for the app.
/// </summary>
/// <param name="sender">PrintDocument</param>
/// <param name="e">Paginate Event Arguments</param>
protected virtual void CreatePrintPreviewPages(object sender, PaginateEventArgs e)
{
// Clear the cache of preview pages
printPreviewPages.Clear();
// Clear the printing root of preview pages
PrintingRoot.Children.Clear();
// This variable keeps track of the last RichTextBlockOverflow element that was added to a page which will be printed
RichTextBlockOverflow lastRTBOOnPage;
// Get the PrintTaskOptions
PrintTaskOptions printingOptions = ((PrintTaskOptions)e.PrintTaskOptions);
// Get the page description to deterimine how big the page is
PrintPageDescription pageDescription = printingOptions.GetPageDescription(0);
// We know there is at least one page to be printed. passing null as the first parameter to
// AddOnePrintPreviewPage tells the function to add the first page.
lastRTBOOnPage = AddOnePrintPreviewPage(null, pageDescription);
// We know there are more pages to be added as long as the last RichTextBoxOverflow added to a print preview
// page has extra content
while (lastRTBOOnPage.HasOverflowContent && lastRTBOOnPage.Visibility == Windows.UI.Xaml.Visibility.Visible)
{
lastRTBOOnPage = AddOnePrintPreviewPage(lastRTBOOnPage, pageDescription);
}
if (pagesCreated != null)
{
pagesCreated.Invoke(printPreviewPages, null);
}
PrintDocument printDoc = (PrintDocument)sender;
// Report the number of preview pages created
printDoc.SetPreviewPageCount(printPreviewPages.Count, PreviewPageCountType.Intermediate);
}
/// <summary>
/// This is the event handler for PrintDocument.GetPrintPreviewPage. It provides a specific print preview page,
/// in the form of an UIElement, to an instance of PrintDocument. PrintDocument subsequently converts the UIElement
/// into a page that the Windows print system can deal with.
/// </summary>
/// <param name="sender">PrintDocument</param>
/// <param name="e">Arguments containing the preview requested page</param>
protected virtual void GetPrintPreviewPage(object sender, GetPreviewPageEventArgs e)
{
PrintDocument printDoc = (PrintDocument)sender;
printDoc.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
}
/// <summary>
/// This is the event handler for PrintDocument.AddPages. It provides all pages to be printed, in the form of
/// UIElements, to an instance of PrintDocument. PrintDocument subsequently converts the UIElements
/// into a pages that the Windows print system can deal with.
/// </summary>
/// <param name="sender">PrintDocument</param>
/// <param name="e">Add page event arguments containing a print task options reference</param>
protected virtual void AddPrintPages(object sender, AddPagesEventArgs e)
{
// Loop over all of the preview pages and add each one to add each page to be printied
for (int i = 0; i < printPreviewPages.Count; i++)
{
// We should have all pages ready at this point...
printDocument.AddPage(printPreviewPages[i]);
}
PrintDocument printDoc = (PrintDocument)sender;
// Indicate that all of the print pages have been provided
printDoc.AddPagesComplete();
}
/// <summary>
/// This function creates and adds one print preview page to the internal cache of print preview
/// pages stored in printPreviewPages.
/// </summary>
/// <param name="lastRTBOAdded">Last RichTextBlockOverflow element added in the current content</param>
/// <param name="printPageDescription">Printer's page description</param>
protected virtual RichTextBlockOverflow AddOnePrintPreviewPage(RichTextBlockOverflow lastRTBOAdded, PrintPageDescription printPageDescription)
{
// XAML element that is used to represent to "printing page"
FrameworkElement page;
// The link container for text overflowing in this page
RichTextBlockOverflow textLink;
// Check if this is the first page ( no previous RichTextBlockOverflow)
if (lastRTBOAdded == null)
{
// If this is the first page add the specific scenario content
page = firstPage;
}
else
{
// Flow content (text) from previous pages
page = new ContinuationPage(lastRTBOAdded);
}
// Set "paper" width
page.Width = printPageDescription.PageSize.Width;
page.Height = printPageDescription.PageSize.Height;
Grid printableArea = (Grid)page.FindName("printableArea");
// Get the margins size
// If the ImageableRect is smaller than the app provided margins use the ImageableRect
double marginWidth = Math.Max(printPageDescription.PageSize.Width - printPageDescription.ImageableRect.Width, printPageDescription.PageSize.Width * ApplicationContentMarginLeft * 2);
double marginHeight = Math.Max(printPageDescription.PageSize.Height - printPageDescription.ImageableRect.Height, printPageDescription.PageSize.Height * ApplicationContentMarginTop * 2);
// Set-up "printable area" on the "paper"
printableArea.Width = firstPage.Width - marginWidth;
printableArea.Height = firstPage.Height - marginHeight;
// Add the (newley created) page to the printing root which is part of the visual tree and force it to go
// through layout so that the linked containers correctly distribute the content inside them.
PrintingRoot.Children.Add(page);
//PrintingRoot.InvalidateMeasure();
PrintingRoot.UpdateLayout();
// Find the last text container and see if the content is overflowing
textLink = (RichTextBlockOverflow)page.FindName("continuationPageLinkedContainer");
// Check if this is the last page
if (!textLink.HasOverflowContent && textLink.Visibility == Windows.UI.Xaml.Visibility.Visible)
{
StackPanel footer = (StackPanel)page.FindName("footer");
footer.Visibility = Windows.UI.Xaml.Visibility.Visible;
}
// Add the page to the page preview collection
printPreviewPages.Add(page);
return textLink;
}
#region Navigation
#endregion