14

How do I print the contents of a TextBox in metro apps? I have read this quickstart guide on MSDN and many online tutorials, but they are very complicated and do not work with TextBox controls, only RichTextBox controls.

How do we print from a TextBox control in a metro app? Is it even possible? How?

Yannick Blondeau
  • 8,867
  • 7
  • 48
  • 67
jay_t55
  • 10,203
  • 26
  • 92
  • 167
  • Sorry, printing *is* complicated. What part didn't work with a regular TextBox? – Cody Gray Mar 22 '13 at 06:20
  • @TwoMore sorry, not a dupe - that question doesn't answer. It doesn't work at all. – jay_t55 Mar 22 '13 at 06:21
  • @CodyGray Indeed, printing does seem to be complicated. Well, all of the code I have seen online deals with RichTextBox controls, and the entire code is based around the fact that you're using a RichTextBox. When I simple change parts here and there so there's no reference to RichTextBox - only TextBox, doesn't work (as I expected) - which leads me to ask - how exactly do we print with TextBox's? It appears that nobody has done this yet. – jay_t55 Mar 22 '13 at 06:24
  • 3
    Why the downvote? This **is NOT** a duplicate. The other questions and answers on here failed to answer my question, and the code provided is for RichTextBox controls, and does NOT work. – jay_t55 Mar 22 '13 at 06:27
  • @CodyGray, printing is _not_ as complicated as you're suggesting. Look at Windows Forms, or even WPF DESKTOP apps, or apps in many other languages; just a couple lines of code and you're done. Windows 8 apps are terrible, and printing in them is the most ass-backward thing I've ever seen. I understand why it is the way it is, but they didn't think to much about it because I can think of a thousand _easier_ ways. – jay_t55 May 20 '13 at 21:03
  • 1
    Doing anything non-trivial takes far more than "a couple lines of code" in Windows Forms. I'll grant you, though, that Windows 8 is poorly conceived and designed. (Also note that I'm not one of the downvoters. This is a perfectly valid question. I was just pressing you to provide more details.) – Cody Gray May 20 '13 at 23:55
  • Windows 8.1 has been released (as Preview) and I'm really disappointed. I really expected it to have better support for printing in Metro apps. Something so simple still doesn't exist anywhere online. Printing from a TextBox. Simple right? On any version of windows, regardless of language, or framework, printing is so simple. Except for Metro apps. They're unnecessarily complicated. Metro is not a good fit for Desktops in general. Great for basic, starter-level tablets. Great for phones. But too poorly designed if you want to get things done efficiently and real customization is non-existent. – jay_t55 Jul 27 '13 at 07:05
  • @CodyGray Its not that complicated. Guys, check my answer below. Its straightforward. You just need to understand the flow of logic here. Printing works on any UIElement...just make sure you style it properly. – Alexandru Dec 15 '13 at 17:43

3 Answers3

7

UPDATE 1

I have created a helper class which simplifies printing text box content. You can add helper class via NuGet. If you want to enhance my existing helper class, fork on GitHub


Here I am giving you the modified print sample from MSDN. I have put textbox you can write anything and that will be printed. Please note I have not done sample which prints textbox text exactly same as it is i.e formatting (bold, italic, underline, colors). I have set hard-coded print format. You can make your own format.

Stack Overflow has character limit in answer and my code is too long so posting CodePaste.net links.

XAML : http://codepaste.net/9nf261

CS : http://codepaste.net/q3hsm3

Please note that I have used some images so put images in "Images" folder

Farhan Ghumra
  • 14,534
  • 5
  • 43
  • 105
  • 4
    Adding a link to a code download is not a good answer. If you take that file off of skydrive then this answer becomes useless. Include the code as part of the answer. – John Koerner Mar 25 '13 at 13:45
  • 2
    I never remove my public samples. Then also I am posting code here – Farhan Ghumra Mar 25 '13 at 13:58
  • @Xyroid thank you for doing this. I ran into a NullReferenceException on line: ` PrintingRoot.Children.Add(page);` but I don't see why anything is null? – jay_t55 Mar 25 '13 at 15:27
  • I didn't face any problem, I recommend you to create new project and use my code from Skydrive. My Skydrive project is tested by me. – Farhan Ghumra Mar 25 '13 at 17:53
  • 2
    I think the fact that the code is too long to fit on SO is a pretty good indication that printing plain text from a TextBox in Metro apps is overly and unnecessarily complicated. – jay_t55 Jul 27 '13 at 07:06
  • Good god. I have posted some *exceptionally* long answers, and I've never hit the length limit for answers on SO. Surely there's a bunch of unnecessary boilerplate in your code, right? Because otherwise, that's totally nuts. Wow. Someone *badly* needs to wrap this all in a library. – Cody Gray Jul 27 '13 at 07:17
  • @CodyGray - my whole purpose now is to do just what you suggested. To wrap it all lin a library freely available to everyone. with straight-to-the-point samples. But I need to learn how first lol. – jay_t55 Jul 27 '13 at 08:11
6

I just created a small winforms-application with a textbox (textBox1) and a button (button1). The code-behind looks like:

public partial class Form1 : Form
{
    public Form1()
    {
           InitializeComponent();
    }

    private void PrintDocumentOnPrintPage(object sender, PrintPageEventArgs e)
    {
        e.Graphics.DrawString(this.textBox1.Text, this.textBox1.Font, Brushes.Black, 10, 25);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        PrintDocument printDocument = new PrintDocument();
        printDocument.PrintPage += PrintDocumentOnPrintPage;
        printDocument.Print();
    }
}

On a click on the button the printing will be done.

Tomtom
  • 8,386
  • 7
  • 45
  • 83
  • 2
    The question is about windows store apps, which is a completely different beast. – John Koerner Mar 25 '13 at 14:00
  • 2
    The question is regarding Windows Store apps, that's quite different from Windows Forms apps. – Farhan Ghumra Mar 25 '13 at 14:01
  • 2
    4 lines of code in WinForms, compared to probably hundreds in a Metro app - and what for????? Just to print the contents of a TextBox which may or may not have just a single character inside of it? Microsoft really stuffed this one up. – jay_t55 Jun 20 '13 at 11:46
0

I urge you to check my question here in which I illustrate one of the simplest cases in which you can print something off a page (and you can add that code onto any page you currently have - just replace the example text box's text I use to whatever your heart desires). The reason why they use the rich text boxes is because it can detect when text overflows off the page, thus they use that information to create a new page with another rich text box until no more overflowing occurs. No matter, you can use your own string parser to split your text up on different pages. Essentially, printing in Windows 8 apps will print any UIElement you want, so you can pretty much XAML align your page programmatically and style it just the way you'd style any other Windows app. Seriously, check the question, it'll be a huge help. I spent hours hacking the PrintSample down to the simplest case until I figured out how it all worked. No point in reinventing the wheel, use my struggles to your advantage, that's what Stack is all about. Cheers!

Edit: I'll pose the code here for your convenience, guys.

Step 1: Add this code to the page with your text box.

        protected PrintDocument printDocument = null;
        protected IPrintDocumentSource printDocumentSource = null;
        internal List<UIElement> printPreviewElements = new List<UIElement>();
        protected event EventHandler pagesCreated;

        protected void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e)
        {
            PrintTask printTask = null;
            printTask = e.Request.CreatePrintTask("C# Printing SDK Sample", sourceRequested =>
            {
                printTask.Completed += async (s, args) =>
                {
                    if (args.Completion == PrintTaskCompletion.Failed)
                    {
                        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
                        {
                            MessageDialog dialog = new MessageDialog("Something went wrong while trying to print. Please try again.");
                            await dialog.ShowAsync();
                        });
                    }
                };
                sourceRequested.SetSource(printDocumentSource);
            });
        }

        protected void RegisterForPrinting()
        {
            printDocument = new PrintDocument();
            printDocumentSource = printDocument.DocumentSource;
            printDocument.Paginate += CreatePrintPreviewPages;
            printDocument.GetPreviewPage += GetPrintPreviewPage;
            printDocument.AddPages += AddPrintPages;
            PrintManager printMan = PrintManager.GetForCurrentView();
            printMan.PrintTaskRequested += PrintTaskRequested;
        }

        protected void UnregisterForPrinting()
        {
            if (printDocument != null)
            {
                printDocument.Paginate -= CreatePrintPreviewPages;
                printDocument.GetPreviewPage -= GetPrintPreviewPage;
                printDocument.AddPages -= AddPrintPages;
                PrintManager printMan = PrintManager.GetForCurrentView();
                printMan.PrintTaskRequested -= PrintTaskRequested;
            }
        }

        protected void CreatePrintPreviewPages(object sender, PaginateEventArgs e)
        {
            printPreviewElements.Clear();
            PrintTaskOptions printingOptions = ((PrintTaskOptions)e.PrintTaskOptions);
            PrintPageDescription pageDescription = printingOptions.GetPageDescription(0);
            AddOnePrintPreviewPage(pageDescription);
            if (pagesCreated != null)
            {
                pagesCreated.Invoke(printPreviewElements, null);
            }
            ((PrintDocument)sender).SetPreviewPageCount(printPreviewElements.Count, PreviewPageCountType.Intermediate);
        }

        protected void GetPrintPreviewPage(object sender, GetPreviewPageEventArgs e)
        {
            ((PrintDocument)sender).SetPreviewPage(e.PageNumber, printPreviewElements[e.PageNumber - 1]);
        }

        protected void AddPrintPages(object sender, AddPagesEventArgs e)
        {
            foreach (UIElement element in printPreviewElements)
            {
                printDocument.AddPage(element);
            }
            ((PrintDocument)sender).AddPagesComplete();
        }

        protected void AddOnePrintPreviewPage(PrintPageDescription printPageDescription)
        {
            TextBlock block = new TextBlock();
            block.Text = "This is an example.";
            block.Width = printPageDescription.PageSize.Width;
            block.Height = printPageDescription.PageSize.Height;
            printPreviewElements.Add(block);
        }
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            RegisterForPrinting();
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            UnregisterForPrinting();
        }

Step 2: Replace block.Text with your desired text.

Step 3: Use a print button to show the print UI:

        private async void PrintDocument(object sender, RoutedEventArgs e)
        {
            await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync();
        }

Step 4: Put RequestedTheme="Light" in your App.xaml and you're done. Note: Might be able to alternatively style the textbox the way you want in this XAML class and not have to set the theme of the entire app.

Step 5 (Later On): You might want to consider adding in your own new page detection logic that keeps calling that method up top to create a new page.

Step 6 (Right Now): Get into a fight with the guy at M$ who's responsible for making us struggle.

Community
  • 1
  • 1
Alexandru
  • 10,808
  • 12
  • 98
  • 183