Powered by MSDN

US - English
NEW! Silverlight 5 is available Learn More

RichTextBox Paginating and Printing RSS

1 reply

Last post Apr 21, 2011 06:30 PM by kmcsql

(0)
  • s_aus_1

    s_aus_1

    0 Points

    4 Posts

    RichTextBox Paginating and Printing

    Oct 19, 2010 11:18 PM | LINK

    Hi,

    I'm having problems formatting a richTextBox for printing.

    I've created a user control containing a richtextbox and have pre-defined paragraphs that I use to populate data in the code behind from a POCO object that I load in another page and pass into the user control via a property.

    Here is the user control:

    <UserControl x:Class="ChaosApplication.Controls.RequestPrintControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" 
        xmlns:ChaosServices="clr-namespace:ChaosApplication.Web.Services"
        xmlns:ChaosDataModels="clr-namespace:ChaosApplication.Web.DataModels"         
        xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices" 
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
    	mc:Ignorable="d">
        <toolkit:BusyIndicator x:Name="busyIndicator">
            <Grid x:Name="LayoutRoot" Background="White">
                <RichTextBox x:Name="printRTB"  Grid.Row="2" Grid.Column="1" Margin="0">
                    <Paragraph x:Name="idParagraph">
                            <Run Text="Request ID " FontWeight="Bold"/><Run x:Name="idRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Request Date: " FontWeight="Bold"/><Run x:Name="dateRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Title: " FontWeight="Bold"/><Run x:Name="titleRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Author:  " FontWeight="Bold"/> <Run x:Name="authorRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="CIP Group: " FontWeight="Bold"/><Run x:Name="groupRun"/>
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Functional Area: " FontWeight="Bold"/><Run  x:Name="areaRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Business Unit: " FontWeight="Bold"/><Run x:Name="buRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Priority: " FontWeight="Bold"/><Run x:Name="priorityRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Status: " FontWeight="Bold"/><Run x:Name="statusRun"/>
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Requirements: " FontWeight="Bold"/><Run x:Name="requirementsRun" />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Summary Description: " FontWeight="Bold"/><Run x:Name="summaryRun"/>
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Benefits: " FontWeight="Bold"/><Run x:Name="benefitsRun"  />
                    </Paragraph>
                    <Paragraph>
                        <Run Text="Objectives Description: " FontWeight="Bold"/><Run x:Name="objectivesRun" />
                    </Paragraph>
                </RichTextBox>
         </Grid>
        </toolkit:BusyIndicator>
    </UserControl>


    in my code behind I call a function to populate the date from my class as follows:

    private void setTextboxData()
    {
      idRun.Text = PrintRequestData.RequestID.ToString();
      dateRun.Text = PrintRequestData.RequestDate.ToString();
      titleRun.Text = PrintRequestData.Title;
      authorRun.Text = PrintRequestData.Author;
      groupRun.Text = PrintRequestData.CIPGroupDesc;
      areaRun.Text = PrintRequestData.AreaName;
      buRun.Text = PrintRequestData.BusinessUnitDesc;
      priorityRun.Text = PrintRequestData.PriorityDesc;
      statusRun.Text = PrintRequestData.StatusDesc;
      requirementsRun.Text = PrintRequestData.RequirementDesc;
      summaryRun.Text = PrintRequestData.SummaryDesc; 
      benefitsRun.Text = PrintRequestData.BenefitsDesc;
      objectivesRun.Text = PrintRequestData.ObjectivesDesc;
    }


    I'm then using a similar methodology to this article: http://www.silverlightshow.net/items/Advanced-printing-in-Silverlight-4.aspx to paginate the data and pass it to the printpagecontrol

        public void Print()
    {
        _printLineIndex = 0;
        _printBlockIndex = 0;
        _printPageCount = 0;
                
        _printDocumentBodyLines = new List<string>();
    
        LayoutRoot.DataContext = PrintRequestData;
        //requestDetailGrid.DataContext = PrintRequestData;
    
        string printInfoText = "Chaos Request Form No: " + RequestID;
    
        setTextboxData();
                
        PrintDocument printDocument = new PrintDocument();
        printDocument.BeginPrint += new EventHandler<BeginPrintEventArgs>(printDocument_BeginPrint);
        printDocument.EndPrint += new EventHandler<EndPrintEventArgs>(printDocument_EndPrint);
        printDocument.PrintPage += new EventHandler<PrintPageEventArgs>(printDocument_PrintPage);
        printDocument.Print(printInfoText);
    
    }
    
    void printDocument_EndPrint(object sender, EndPrintEventArgs e)
    {
        busyIndicator.IsBusy = false;
    }
    
    void printDocument_BeginPrint(object sender, BeginPrintEventArgs e)
    {
        busyIndicator.IsBusy = true;
    }
    
    void printDocument_PrintPage(object sender, PrintPageEventArgs e)
    {
    
        PrintPageControl page = new PrintPageControl();
        //increment the page count
        _printPageCount++;
        Paragraph p;
        Run r;
                
        int lineCount = 0;
        int blockCount = 0;
                
        string headerText = "Chaos CIP Request";
        string footerText = "Page " + _printPageCount;
    
        page.SetHeaderAndFooterText(headerText, footerText);
    
        //e.PageVisual = LayoutRoot;
    
        int numberOfLinesAdded = 0;
        int numberOfBlocksAdded = 0;
    
        foreach (Block b in printRTB.Blocks)
        {
            if (b is Paragraph)
            {
                if (blockCount>=_printBlockIndex )
                {
                    numberOfLinesAdded = 0;
                    p = new Paragraph();
                    p = b as Paragraph;
    
                    foreach (Run run in p.Inlines)
                    {
                               
                        if (lineCount >= _printLineIndex)
                        {
                            r = new Run();
                            r.Text = run.Text;
                            r.TextDecorations = run.TextDecorations;
                            r.FontWeight = run.FontWeight;
                            page.AddLine(r);
                            page.Measure(new Size(e.PrintableArea.Width, double.PositiveInfinity));
                            if (page.DesiredSize.Height > e.PrintableArea.Height
                                && numberOfLinesAdded > 0)
                            {
                                page.RemoveLastLine();
                                e.HasMorePages = true;
                                _printLineIndex = numberOfLinesAdded;
                                _printBlockIndex += numberOfBlocksAdded;
                                break;
                            }
                            numberOfLinesAdded++;
                        }
                        lineCount++;
                    }
                           
                    if (e.HasMorePages)
                        break;
                    numberOfBlocksAdded++;
                            
                }
                blockCount++;
                       
            }
        }
    
        e.PageVisual = page;
                 
    }
            
    

    Print() is called from a button click.

    the printpagecontrol looks like this: (XAML)

    <UserControl x:Class="ChaosApplication.Controls.PrintPageControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid x:Name="documentRoot">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition x:Name="leftMargin" Width="20"/>
                    <ColumnDefinition/>
                    <ColumnDefinition x:Name="rightMargin" Width="20"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition x:Name="topMargin" Height="20"/>
                    <RowDefinition x:Name="headerRow" Height="25"/>
                    <RowDefinition />
                    <RowDefinition x:Name="footerRow" Height="25"/>
                    <RowDefinition x:Name="bottomMargin" Height="20"/>
                </Grid.RowDefinitions>
    
                <TextBlock x:Name="headerTextBlock" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" FontFamily="Arial" FontSize="20" />
                <RichTextBox x:Name="bodyRichTextBox" Grid.Row="2" Grid.Column="1" TextWrapping="Wrap" />
                <TextBlock x:Name="footerTextBlock" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Center"/>
    
            </Grid>
        </Grid>
    </UserControl>
    


    PrintpageControl (Code Behind):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    
    namespace ChaosApplication.Controls
    {
        public partial class PrintPageControl : UserControl
        {
    
    
            public PrintPageControl()
            {
                InitializeComponent();
    
            }
    
            public void SetHeaderAndFooterText(string header, string footer)
            {
                headerTextBlock.Text = header;
                footerTextBlock.Text = footer;
            }
    
            public void AddLine(Run r)
            {
                Paragraph p = new Paragraph();
                p.Inlines.Add(r);
                bodyRichTextBox.Blocks.Add(p);
            }
    
            public void AddLine(Span s)
            {
                Paragraph p = new Paragraph();
                p.Inlines.Add(s);
                bodyRichTextBox.Blocks.Add(p);
            }
    
            public void RemoveLastLine()
            {
                BlockCollection bc = bodyRichTextBox.Blocks;
                //get the last block
                Block b =  bc.ElementAt(bodyRichTextBox.Blocks.Count - 1);
                Paragraph p = b as Paragraph;
    
                p.Inlines.RemoveAt(p.Inlines.Count - 1);
    
            }
            
        }
    }


    This all works however the pages are determined based on paragraphs, rather than lines of text within paragraphs and the formatting is poor.

    What I would like to achieve is to have the field titles in one column and the values in another column and nicely paginated based on lines of text rather than paragraphs. I initially tried using a grid but couldn't work out how to paginate it.

    Any suggestions would be greatlly appreciated.

    thanks






  • kmcsql

    kmcsql

    Member

    2 Points

    1 Post

    Re: RichTextBox Paginating and Printing

    Apr 21, 2011 06:30 PM | LINK

    You are on the right path

    Set up your DocumetBodylines as List<string> ... fr each paragraph and each run .. add the run.Text to the string list

     

    Create a DocumentFontWeight List<FontWeight> .. and add the fontweight from run at the same time as you add the string.

     

    You can do this for each font and the text decoration as well.

     

    Also, change back to a TextBlock in the PrintPage Usercontrol for the body

    Samples:

    DocumentBodyLines =

    new List<string

    >();

    DocumentFontWeight =

    new List<FontWeight

    >();

     

    int

    blockCount = 0;

     

    int

    lineCount = 0;

     

    foreach (Block b in

    rtb.Blocks)

    {

     

    if (b is Paragraph

    )

    {

     

    Paragraph p = new Paragraph

    ();

    p = b

    as Paragraph

    ;

     

     

    foreach (Run run in

    p.Inlines)

    {

    DocumentBodyLines.Add(run.Text);

    DocumentFontWeight.Add(run.FontWeight);

    lineCount++;

    }

    blockCount++;

    }

    }

    The Addline in the PrintPage Usercontrol:

     

    public void AddLine(string line, FontWeight

    weight )

    {

    bodyTextBlock.Inlines.Add(line);

     

    int

    oIndex = bodyTextBlock.Inlines.Count - 1;

    bodyTextBlock.Inlines[oIndex].FontWeight = weight;

    bodyTextBlock.Inlines.Add(

    new LineBreak

    ());

     

    }

     And the print page handler

    private void printDocument_PrintPage(object sender, PrintPageEventArgs

    e)

    {

    PEN_SL_C_MANAGER.Controls.

    PrintPage page = new PEN_SL_C_MANAGER.Controls.PrintPage

    ();

    page.SetHeaderAndFooterText(DocumentTitle,

    "Date"

    );

     

    int

    numberOfLinesAdded = 0;

     

    while

    (LineIndex < DocumentBodyLines.Count)

    {

    page.AddLine(DocumentBodyLines[LineIndex], DocumentFontWeight[LineIndex]);

    page.Measure(

    new Size(e.PrintableArea.Width, double

    .PositiveInfinity));

     

    if

    (page.DesiredSize.Height > e.PrintableArea.Height && numberOfLinesAdded > 1)

    {

    page.RemoveLastLine();

    e.HasMorePages =

    true

    ;

     

    break

    ;

    }

    LineIndex++;

    numberOfLinesAdded++;

    }

    e.PageVisual = page;

    }