Exercise 2 –Text Services and Printing

In this exercise we'll learn how we can perform operations such as using the clipboard to copy and paste text into the rich text area and print our rich text content.

Task 1 – Clipboard Support

Silverlight 4 provides support for clipboard operations. In task we'll add functionality to support cut, copy and paste.

  1. Open the MainPage.xaml file, and locate the comment remark <!-- TODO - Clipboard Buttons-->. Add the following code for the Cut, Copy and Paste buttons.

    XAML

    <Button x:Name="btnPaste" Margin="17,-22,33,24" Grid.Row="1" HorizontalAlignment="Left"> <ToolTipService.ToolTip> <ToolTip FontSize="16" Content="Paste"/> </ToolTipService.ToolTip> <Image Source="Images/Paste_big.png" Height="32" Width="29"/> </Button> <Button x:Name="btnCut" Margin="0,0,17,0" HorizontalAlignment="Right" Width="22" VerticalAlignment="Bottom"> <ToolTipService.ToolTip> <ToolTip FontSize="16" Content="Cut"/> </ToolTipService.ToolTip> <Image Source="Images/Cut.png" d:IsLocked="True"/> </Button> <Button x:Name="btnCopy" Margin="0,5,17,0" VerticalAlignment="Top" Grid.Row="1" HorizontalAlignment="Right" Width="22"> <ToolTipService.ToolTip> <ToolTip FontSize="16" Content="Copy"/> </ToolTipService.ToolTip> <Image Source="Images/Copy.png" d:IsLocked="True"/> </Button>
  2. Add a default event handler for the Click event in each of the buttons above.
  3. In order to access the clipboard, we'll use the Clipboard class introduced in Silverlight 4 which supports saving and loading strings in the clipboard. Add the following code to the event handler for btnCopy to allow saving strings in the clipboard:

    C#

    Clipboard.SetText(rtb.Selection.Text);ReturnFocus();
  4. Find the Click event handler for the btnPaste button and add the following code to read strings from the clipboard

    C#

    rtb.Selection.Text = Clipboard.GetText();ReturnFocus();
  5. Find the Click event handler for the btnCut button and add the following code:

    C#

    Clipboard.SetText(rtb.Selection.Text); rtb.Selection.Text = "";ReturnFocus();
  6. Compile and run the application by pressing F5. Add some text in the RichTextBox and press the Copy button. Open Notepad and paste the string (CTRL+V).
  7. Return to the application, press the Create New document button (click OK if prompted) and then press the Paste button. The copied text will be pasted in the RichTextBox. The Text Editor application now has clipboard support.

Task 2 – Printing from Silverlight

Silverlight 4 enables developers to use installed printers in order to print application content. In this exercise we will use this functionality and print the document content.

  1. To print the contents of the RichTextBox we will use the PrintDocument class introduced in Silverlight 4. Open the MainPage.xaml file, and locate the comment remark <!-- TODO - Print Buttons-->. Add the following code for the Print button:

    C#

    <Button x:Name="btnPrint" Grid.Column="3" Margin="20,-22,0,24" HorizontalAlignment="Left" Grid.Row="1"> <ToolTipService.ToolTip> <ToolTip FontSize="16" Content="{Binding tooltip_Print, Source={StaticResource localizedStrings}}"/> </ToolTipService.ToolTip> <Image Source="Images/Print_big.png" Width="30"/> </Button>
  2. Add a default event handler for the Click event for the Print button.
  3. Navigate to the event handler function and add the following code

    C#

    PrintDocument theDoc = new PrintDocument(); string DocumentName = "Silverlight 4 Text Editor - Opened Document"; theDoc.Print(DocumentName);
  4. As you can see, we've called the Print method, but we haven't told it what to print. To set the printed area we'll need to handle the PrintDocument.PrintPage event. Add the following code to handle the event (place the code before calling the "Print" method)

    C#

    theDoc.PrintPage += (s, args) => { args.PageVisual = rtb; args.HasMorePages = false; };
  5. We'll also add a MessageBox to notify the user the printing was successful. Place the following code before calling the Print method:

    C#

    theDoc.EndPrint += (s, args) => { MessageBox.Show("The document printed successfully", "Text Editor", MessageBoxButton.OK); };
  6. Compile and run the application by pressing F5. Enter text and add an image to the content, then press the Print button.
  7. In the printing dialog, select one of the installed printers or print to the "Microsoft XPS Document Writer" printer. Save the file and after the printing is finished, open the .xps file. Examine how the printed content is similar to the content displayed in the rich text control.

Task 3 – Highlight and XAML functionality

In this exercise we will build upon the controls added thus far. We will add highlight functionality to the RichTextBox. We will also add the ability to toggle between traditional rich text view and the Xaml markup generated for the contents of the RichTextBox.

  1. Open MainPage.xaml and locate the comment remark <!-- TODO - Display, Highlight, Xaml Buttons-->. Add the following code for the Highlight and Xaml buttons:

    XAML

    <!-- Highlight Button--> <ToggleButton x:Name="btnHighlight" Checked="btnHighlight_Checked" Unchecked="btnHighlight_Checked" Margin="17,-22,15,24" Grid.Column="5" Grid.Row="1" HorizontalAlignment="Left"> <ToolTipService.ToolTip> <ToolTip FontSize="16" Content="Show Highlight"/> </ToolTipService.ToolTip> <Image Source="Images/Annotation_New.png"/> </ToggleButton> <!-- Xaml Buttons--> <ToggleButton x:Name="btnMarkUp" Checked="btnMarkUp_Checked" Unchecked="btnMarkUp_Checked" Margin="10,-22,10,24" Grid.Column="6" Grid.Row="1" HorizontalAlignment="Left"> <ToolTipService.ToolTip> <ToolTip FontSize="16" Content="Show XAML"/> </ToolTipService.ToolTip> <TextBlock FontSize="25" Text="&lt;&lt;>>"/> </ToggleButton>
  2. Examine the code and above and note that the event handlers for Checked and Unchecked have already been assigned to each Toggle Button control.
  3. Right-click on the Checked event handler for the Xaml Markup Button and navigate to the corresponding code in MainPage.xaml.cs. Place the following code into the event:

    C#

    if (btnMarkUp.IsChecked.Value) { xamlTb.Visibility = System.Windows.Visibility.Visible; xamlTb.IsTabStop = true; xamlTb.Text = rtb.Xaml; } else { rtb.Xaml = xamlTb.Text; xamlTb.Visibility = System.Windows.Visibility.Collapsed; xamlTb.IsTabStop = false; }
  4. Locate the Highlight Button's btnHighlight_Checked method in the code. As you study the code you'll see how the TextPointer tracks the current position of the caret to gain a starting point. The struct Rect is used to find the populated area of the rectangle that the user (using Mouse Events) placed over the text.
  5. Compile and run the application by pressing F5. Enter text, click the Highlight Button, and as you enter the RichTextBox your mouse will highlight the current row you are on. Left mouse click and drag across some text and you can specifically highlight a certain part of the text. Clicking the Highlight Button again will turn off this feature.
  6. Now click the Xaml Button. You will see Xaml markup code used to display the presentation version of the text within the RichTextBox.

Task 4 – Drag and Drop Support

New to Silverlight 4 is the Drop Target API. In this exercise we will demonstrate the use of this API by adding drag and drop functionality of Word documents and text files right into the RichTextBox.

  1. Open MainPage.xaml file and locate the RichTextBox control named rtb. Add the following attributes to it:
  2. Drop="rtb_Drop" AllowDrop="True"
  3. Open MainPage.xaml.cs and add the following code:

    C#

    private void rtb_Drop(object sender, System.Windows.DragEventArgs e) { VisualStateManager.GoToState(this, "Normal", true); if (e.Data != null) { IDataObject f = e.Data as IDataObject; if (f != null) { object data = f.GetData(DataFormats.FileDrop); FileInfo[] files = data as FileInfo[]; if (files != null) { foreach (FileInfo file in files) { if (file != null) { if (file.Extension.Equals(".txt")) { try { Stream sr = file.OpenRead(); string contents; using (StreamReader reader = new StreamReader(sr)) { contents = reader.ReadToEnd(); } rtb.Selection.Text = contents; } catch (IOException ex) { //check if message is for a File IO docOpenedError(); } } else if (file.Extension.Equals(".docx")) { try { Stream sr = file.OpenRead(); string contents; StreamResourceInfo zipInfo = new StreamResourceInfo(sr, null); StreamResourceInfo wordInfo = Application.GetResourceStream(zipInfo, new Uri("word/document.xml", UriKind.Relative)); using (StreamReader reader = new StreamReader(wordInfo.Stream)) { contents = reader.ReadToEnd(); } XDocument xmlFile = XDocument.Parse(contents); XNamespace w = "https://schemas.openxmlformats.org/wordprocessingml/2006/main"; var query = from xp in xmlFile.Descendants(w + "p") select xp; Paragraph p = null; Run r = null; foreach (XElement xp in query) { p = new Paragraph(); var query2 = from xr in xp.Descendants(w + "r") select xr; foreach (XElement xr in query2) { r = new Run(); var query3 = from xt in xr.Descendants() select xt; foreach (XElement xt in query3) { if (xt.Name == (w + "t")) r.Text = xt.Value.ToString(); else if (xt.Name == (w + "br")) p.Inlines.Add(new LineBreak()); } p.Inlines.Add(r); } p.Inlines.Add(new LineBreak()); rtb.Blocks.Add(p); } } catch (IOException ex) { //check if message is for a File IO docOpenedError(); } } } } } } } ReturnFocus(); } private void docOpenedError() { //check if message is for a File IO MessageBox.Show("The document may already be open. Please ensure no other application has the document opened or locked and try again", "Drag & Drop Error", MessageBoxButton.OK); }
  4. Compile and run the application by pressing F5. Locate the "Helpers" folder contained within this Lab's folders (ie: ....\RichTextBox\Source\Helpers). Drag and drop the file SampleTextFile.txt into the Rich Text Box control. Now do the same for the file Hamlet.docx.