鸿志之家

让我们一起来学习体验微软Silverlight的魅力
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Silverlight 文本编辑器示例

Posted on 2012-02-02 11:00  大漠、天使、飞烟  阅读(1612)  评论(1)    收藏  举报

Silverlight 文本编辑器示例

此主题尚未评级 评价此主题
 
Silverlight
 

本主题提供有关 Silverlight 文本编辑器示例的概述。使用此示例,您可以键入和编辑富文本并执行若干操作。操作包括格式化文本、插入图像、插入日历、插入数据网格、从右到左显示文本、打印以及访问剪贴板。此示例基于 Silverlight 4 中新的 RichTextBox 控件。此示例还演示 Silverlight 4 中的一些其他新功能。下图显示此示例的内容:

Silverlight 文本编辑器

若要试用此示例,请单击以下链接。

运行此示例

下载此示例

您需要以下组件才能生成 Silverlight 文本编辑器:

  • Silverlight 4.

  • 用于 Visual Studio 2010 的 Silverlight 4 Tools.

  • Visual Studio 2010.

可以从 Silverlight 下载站点下载所有 Silverlight 软件。

Silverlight 文本编辑器用户界面大体由以下三个部分组成:

  • 一个名为 LayoutRoot  Grid,它占据整个浏览器空间。它具有 Silverlight 徽标和示例区域。示例区域由以下各部分组成:

  • 一个名为 ToolBarGrid  Grid,它承载水平工具栏。此工具栏具有一组按钮,您可以使用它们对 RichTextBox 执行各种操作。

  • 一个名为 RTBGrid  Grid,它承载富文本编辑器。此编辑器使用一个 RichTextBox 控件,在此控件中您可以输入和编辑富文本。

    Silverlight 文本编辑器用户界面

工具栏

工具栏承载在名为 ToolBarGrid  Grid 中。ToolBarGrid 具有两行和七列。第一行没有任何子项,用于向第二行添加填充。第二行承载工具栏按钮。每列都用于承载工具栏的一部分,例如,“剪贴板”“字体”等等。

将工具栏的一个部分视为一个示例。ToolBarGrid (Grid.Column = 1) 上的第二列承载工具栏的“字体”部分。这一部分包含七个控件。下表列出“字体”部分的各个组成部分以及用于创建每个部分的控件。

 

部件

所用控件

字体名称

ComboBox

字体大小

ComboBox

粗体格式

Button

斜体格式

Button

下划线格式

Button

字体颜色

ComboBox

节标题

TextBlock

字体名称和字体大小 ComboBox 控件通过设置适当的边距值来定位。Button 控件和字体颜色 ComboBox 通过使用水平定位的 StackPanel 布局来进行定位。节标题 TextBlock 通过适当的边距值来进行定位。下面的 XAML 显示工具栏的“字体”部分。

 
<!--Fonts Toolbar Section-->
<ComboBox x:Name="cmbFonts" ...
    <ComboBoxItem Content="Arial" ...
    <ComboBoxItem Content="Arial Black" ...
    ...
</ComboBox>

<ComboBox x:Name="cmbFontSizes" …
    <ComboBoxItem Content="8" Tag="8"/>
    <ComboBoxItem Content="9" Tag="9"/>
    ...
</ComboBox>

<StackPanel Grid.Column="1" Grid.Row="1" ...
    <!--Buttons-->
    <Button x:Name="btnBold" ...
    <Button x:Name="btnItalic" ...
    <Button x:Name="btnUnderline" ...
    <ComboBox x:Name="cmbFontColors" ...
        <ComboBoxItem Tag="FFFF0000">
        <ComboBoxItem Tag="FF008000">
        ...
    </ComboBox>
</StackPanel>

编辑器

此编辑器承载在名为 RTBGrid  Grid 中。下表列出了 RTBGrid 的子元素。

 

子元素

名称

说明

Rectangle

 

用作围绕 RichTextBox 的边界。

RichTextBox

rtb

用于输入和编辑丰富的内容。

Canvas

highlightCanvas

当您在工具栏中单击“突出显示”按钮时使用。

TextBox

xamlTB

当您在工具栏中单击“XAML”按钮时,用于显示 XAML。此 TextBox 在默认情况下处于隐藏状态,仅当您单击工具栏中的“XAML”按钮时才显示。

下面的 XAML 显示了 RTBGrid

 
<Grid Name="RTBGrid" Grid.Row="1">
    <Rectangle Fill="White" Margin="0,1,1,0">
        <Rectangle.Effect>
            <DropShadowEffect ShadowDepth="1" Direction="371" BlurRadius="7" Opacity="0.345"/>
        </Rectangle.Effect>
    </Rectangle>
    <RichTextBox x:Name="rtb" AllowDrop="True" BorderBrush="{x:Null}" Margin="8,10,0,8" MouseRightButtonDown="rtb_MouseRightButtonDown" MouseRightButtonUp="rtb_MouseRightButtonUp" Drop="rtb_Drop" MouseMove="rtb_MouseMove" DragEnter="rtb_DragEnter" DragLeave="rtb_DragLeave" TextWrapping="Wrap" Style="{StaticResource RichTextBoxStyle1}" VerticalScrollBarVisibility="Auto" FontSize="20" />
    <Canvas x:Name="highlightCanvas" IsHitTestVisible="False" Margin="8,10,0,8"/>
    <TextBox x:Name="xamlTb" IsTabStop="False" FontSize="20" FontFamily="Lucida Console" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Visibility="Collapsed"/>
</Grid>


通过 Silverlight 文本编辑器示例,您可以执行通过使用 Silverlight 4 中的某些新功能实现的各种富文本编辑操作。以下各节说明这些功能。

初始化

当您运行 Silverlight 文本编辑器示例时,将加载此示例及其初始内容。此内容以 XAML 格式存储在 sample.sav 文件中。sample.sav 文件作为资源添加到项目中,并使用RichTextBox.Xaml 属性进行加载。下面的代码说明如何加载 .sav 文件。

 
//Initialize the RichTextBox. The intial text is saved as XAML inthe Hamlet.docx file.
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    rtb.Xaml = XElement.Load("/RichNotepad;component/sample.sav").ToString();
}


剪贴板

可以使用工具栏的“剪贴板”部分中的“剪切”“复制”“粘贴”按钮在编辑器中剪切、复制或粘贴所选文本。这是通过使用 Silverlight 4 中的新 Clipboard 对象来实现的,如下面的代码所示。

 
//Cut the selected text
private void btnCut_Click(object sender, RoutedEventArgs e)
{
    Clipboard.SetText(rtb.Selection.Text);
    rtb.Selection.Text = "";
    ReturnFocus();
}

//Copy the selected text
private void btnCopy_Click(object sender, RoutedEventArgs e)
{
    Clipboard.SetText(rtb.Selection.Text);
    ReturnFocus();
}

//paste the text
private void btnPaste_Click(object sender, RoutedEventArgs e)
{
    rtb.Selection.Text = Clipboard.GetText();
    ReturnFocus();
}


上下文菜单

还可以通过上下文菜单剪切、复制和粘贴所选文本。此上下文菜单在您右键单击编辑器时出现。右键单击鼠标事件是 Silverlight 4 中的一项新功能。 下图显示了上下文菜单。

上下文菜单

该上下文菜单是使用 Popup 控件实现的。上下文菜单的逻辑主要在项目的 ContextMenu.cs 和 RTBContextMenu.cs 文件中。

ContextMenu 是一个抽象类,它提供用于创建、显示和关闭上下文菜单的基本功能。可以从该基类派生来创建所需的上下文菜单。ContextMenu 类提供了以下功能:

  • 定义名为 GetContent 的抽象方法。

    此派生类必须实现 GetContent 方法,才能创建上下文菜单的所需内容。GetContent 方法返回一个 FrameworkElement 对象,该对象具有上下文菜单的内容。

     
    //Abstract function that the child class needs to implement to return the framework element that needs to be displayed in the popup window.
    protected abstract FrameworkElement GetContent();
    
    
    
  • 构造和显示上下文菜单。

    用于构造和显示上下文菜单的逻辑在 ContextMenu 类的 Show 方法中执行。在 Show 方法中,Popup 控件进行实例化,其大小设置为示例的宽度和高度。GetContent 方法返回的 FrameworkElement 作为 Popup 控件的子项添加。在 Show 方法采取的位置中,上下文菜单必须显示为参数。此位置设置为弹出式控件中 FrameworkElement 的边距。下面的代码演示如何实现 Show 方法。

     
    //Intiialize and show the popup window. This is the public method to call, to display the ContextMenu at the desired location. 
    public void Show(Point location)
    {
        if (_isShowing)
            throw new InvalidOperationException();
    
        _isShowing = true;
        _location = location;
        ConstructPopup();
        _popup.IsOpen = true;
    }
    
    
    
  • 关闭上下文菜单。

  • 提供一个事件处理程序,供您在上下文菜单之外单击时用来关闭上下文菜单。

RTBContextMenu 类派生自 ContextMenu 类并执行以下操作:

  • 实现在 ContextMenu 类中定义的 GetContent 方法。GetContent 方法构造并返回 FrameworkElement。然后,它用于 ContextMenu 类的 Show 方法中以构造上下文菜单。下面的代码显示由 RTBContextMenu 类实现的 GetContent 方法。

     
    //Construct the context menu and return the parent FrameworkElement. 
    protected override FrameworkElement GetContent()
    {
        Border border = new Border() { BorderBrush = new SolidColorBrush(Color.FromArgb(255, 167,171,176)), BorderThickness = new Thickness(1), Background = new SolidColorBrush(Colors.White) };
        border.Effect = new DropShadowEffect() { BlurRadius = 3, Color = Color.FromArgb(255, 230, 227, 236) };
    
        Grid grid = new Grid() { Margin = new Thickness(1) };
        grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(25) });
        grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(105) });
    
        grid.Children.Add(new Rectangle() { Fill = new SolidColorBrush(Color.FromArgb(255, 233, 238, 238)) });
        grid.Children.Add(new Rectangle() { Fill = new SolidColorBrush(Color.FromArgb(255, 226, 228, 231)), HorizontalAlignment = HorizontalAlignment.Right, Width = 1 });
    
        //cut
        Button cutButton = new Button() { Height = 22, Margin = new Thickness(0, 0, 0, 0), HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Top, HorizontalContentAlignment = HorizontalAlignment.Left };
        cutButton.Style = Application.Current.Resources["ContextMenuButton"] as Style;
        cutButton.Click += cut_MouseLeftButtonUp;
        Grid.SetColumnSpan(cutButton, 2);
    
        StackPanel sp = new StackPanel() { Orientation = Orientation.Horizontal };
    
        Image cutImage = new Image() { HorizontalAlignment = HorizontalAlignment.Left, Width = 16, Height = 16, Margin = new Thickness(1, 0, 0, 0) };
        cutImage.Source = new BitmapImage(new Uri("/RichNotepad;component/images/cut.png", UriKind.RelativeOrAbsolute));
        sp.Children.Add(cutImage);
    
        TextBlock cutText = new TextBlock() { Text = "Cut", HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(16, 0, 0, 0) };
        sp.Children.Add(cutText);
    
        cutButton.Content = sp;
    
        grid.Children.Add(cutButton);
    
        //copy
        Button copyButton = new Button() { Height = 22, Margin = new Thickness(0, 24, 0, 0), HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Top, HorizontalContentAlignment = HorizontalAlignment.Left };
        copyButton.Style = Application.Current.Resources["ContextMenuButton"] as Style;
        copyButton.Click += copy_MouseLeftButtonUp;
        Grid.SetColumnSpan(copyButton, 2);
    
        sp = new StackPanel() { Orientation = Orientation.Horizontal };
    
        Image copyImage = new Image() { HorizontalAlignment = HorizontalAlignment.Left, Width = 16, Height = 16, Margin = new Thickness(1, 0, 0, 0) };
        copyImage.Source = new BitmapImage(new Uri("/RichNotepad;component/images/copy.png", UriKind.RelativeOrAbsolute));
        sp.Children.Add(copyImage);
    
        TextBlock copyText = new TextBlock() { Text = "Copy", HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(16, 0, 0, 0) };
        sp.Children.Add(copyText);
    
        copyButton.Content = sp;
    
        grid.Children.Add(copyButton);          
    
        //paste
        Button pasteButton = new Button() { Height = 22, Margin = new Thickness(0, 48, 0, 0), HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Top, HorizontalContentAlignment = HorizontalAlignment.Left };
        pasteButton.Style = Application.Current.Resources["ContextMenuButton"] as Style;
        pasteButton.Click += paste_MouseLeftButtonUp;
        Grid.SetColumnSpan(pasteButton, 2);
    
        sp = new StackPanel() { Orientation = Orientation.Horizontal };
    
        Image pasteImage = new Image() { HorizontalAlignment = HorizontalAlignment.Left, Width = 16, Height = 16, Margin = new Thickness(1, 0, 0, 0) };
        pasteImage.Source = new BitmapImage(new Uri("/RichNotepad;component/images/paste.png", UriKind.RelativeOrAbsolute));
        sp.Children.Add(pasteImage);
    
        TextBlock pasteText = new TextBlock() { Text = "Paste", HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(16, 0, 0, 0) };
        sp.Children.Add(pasteText);
    
        pasteButton.Content = sp;
    
        grid.Children.Add(pasteButton);
    
        border.Child = grid;
    
        return border;
    }
    
    
    
  • 当在上下文菜单中单击对应的按钮时,针对剪切、复制、粘贴操作处理 MouseLeftButtonUp 事件。下面的代码显示用于剪切、复制、粘贴操作的事件处理程序。

     
    //handle the cut, copy and paste actions when the appropriate button on the context menu is clicked. 
    void cut_MouseLeftButtonUp(object sender, RoutedEventArgs e)
    {
        Clipboard.SetText(rtb.Selection.Text);
        rtb.Selection.Text = "";
        Close();
    }
    
    void copy_MouseLeftButtonUp(object sender, RoutedEventArgs e)
    {
        Clipboard.SetText(rtb.Selection.Text);
        Close();
    }
    
    void paste_MouseLeftButtonUp(object sender, RoutedEventArgs e)
    {
        rtb.Selection.Text = Clipboard.GetText();
        Close();
    }
    
    
    

字体

通过 Silverlight 文本编辑器示例,您可以将粗体、斜体、下划线、字体类型、字体大小和字体颜色格式应用于所选文本。若要应用字体格式,请对 RichTextBox 中的所选文本使用TextSelection.ApplyPropertyValue 方法以及适当的依赖项属性和属性值。下表汇总了您可以用来应用字体格式的依赖项属性和属性值。

 

字体格式

依赖项属性

属性值

粗体

FontWeightProperty

使用 FontWeights.Bold 属性将粗体格式应用于所选文本。请使用

FontWeights.Normal 从所选文本中删除粗体格式。

斜体

FontStyleProperty

使用 FontStyles.Italic 属性将斜体格式应用于所选文本。

使用 FontStyles.Normal 从所选文本中删除普通格式。

Underline

TextDecorationsProperty

使用 TextDecorations.Underline 属性将下划线格式应用于所选文本。

 TextDecorationsProperty 设置为 null 以从所选文本中删除下划线格式。

字体类型

FontFamilyProperty

使用通过所需的字体名称构建的 FontFamily 对象来指定字体。

字体大小

FontSizeProperty

使用 double 值指定字体大小。

字体颜色

ForegroundProperty

使用 SolidColorBrush 对象指定所需颜色。

以下代码说明如何在 Silverlight 文本编辑器示例中应用字体格式。

RichNotepadSnippets#Font1, Font2

Insert

您可以将元素(例如,图像、超链接、数据网格和日历)插入到 Silverlight 文本编辑器示例中。

使用“插入图像”按钮可以在编辑器中的当前位置插入图像。此图像首先通过使用 Image 对象创建,该对象指向用于指定图像位置的 URI。然后,使用 InlineUIContainer 将其插入到RichTextBox 中。此示例插入名为 desert.jpg 且存储为项目资源的图像。但是,您可以通过传递适当的 URI 插入任何其他图像。

下面的代码显示如何插入图像。

 
//Insert an image into the RichTextBox
private void btnImage_Click(object sender, RoutedEventArgs e)
{
    InlineUIContainer container = new InlineUIContainer();

    container.Child = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/Desert.jpg", UriKind.RelativeOrAbsolute), 200, 150);

    rtb.Selection.Insert(container);
    ReturnFocus();
}

private static Image createImageFromUri(Uri URI, double width, double height)
{
    Image img = new Image();
    img.Stretch = Stretch.Uniform;
    img.Width = width;
    img.Height = height;
    BitmapImage bi = new BitmapImage(URI);
    img.Source = bi;
    img.Tag = bi.UriSource.ToString();
    return img;
}


用于将任何其他 UIElement 插入到 RichTextBox 中的过程与上面所述的用于插入 Image 的过程相同。此示例使用同一个过程来插入 DataGrid  Calendar 对象。

使用“插入超链接”按钮可以将超链接插入到编辑器中。超链接通过使用 Hyperlink 元素插入。NavigateUri 属性用于指定 URI。当您单击“插入超链接”按钮时,将显示“插入 URL”对话框,如下图中所示。

插入超链接

“插入 URL”对话框是一个 ChildWindow 控件,使您能够为超链接输入“目标 URL”“URL 说明”。下面的代码演示如何实现超链接插入。

 
//Insert a hyperlink
private void btnHyperlink_Click(object sender, RoutedEventArgs e)
{
    InsertURL cw = new InsertURL(rtb.Selection.Text);
    cw.HasCloseButton = false;

    //Hook up an event handler to the Closed event on the ChildWindows cw. 
    cw.Closed += (s, args) =>
    {
        if (cw.DialogResult.Value)
        {
            Hyperlink hyperlink = new Hyperlink();
            hyperlink.TargetName = "_blank";
            hyperlink.NavigateUri = new Uri(cw.txtURL.Text);

            if (cw.txtURLDesc.Text.Length > 0)
                hyperlink.Inlines.Add(cw.txtURLDesc.Text);
            else
                hyperlink.Inlines.Add(cw.txtURL.Text);

            rtb.Selection.Insert(hyperlink);
            ReturnFocus();
        }
    };
    cw.Show();
}


当您在“插入 URL”对话框中单击“确定”“取消”按钮时,将验证“目标 URL”值。将在 Closing 事件处理程序中执行此验证。验证将在 Closing 事件而非 Closed 事件中执行,因为这允许您在验证失败时使对话框保留为打开状态。如果 URI 有效,则在 RichTextBox 中的当前选择位置创建和插入一个新的 Hyperlink 对象。

打印

可以使用“打印”按钮打印编辑器的内容。打印是 Silverlight 4 中的一项新功能。当您单击“打印”按钮时,将显示“打印预览”对话框。“打印预览”对话框是一个 ChildWindow 对象,它具有要打印的内容的图像。下图显示了“打印预览”对话框。

打印预览

此图像是使用一个将 RichTextBox 对象作为参数的 WriteableBitmap 对象创建的。下面说明了用于创建“打印预览”对话框的 XAML 和用于创建 WriteableBitmap 图像的代码。

 
<!-- NOTE: 
  By convention, the sdk prefix indicates a URI-based XAML namespace declaration 
  for Silverlight SDK client libraries. This namespace declaration is valid for 
  Silverlight 4 only. In Silverlight 3, you must use individual XAML namespace 
  declarations for each CLR assembly and namespace combination outside the scope 
  of the default Silverlight XAML namespace. For more information, see the help 
  topic "Prefixes and Mappings for Silverlight Libraries". 
-->
    <sdk:ChildWindow x:Class="RichNotepad.PrintPreview"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
           Width="400" Height="300"
           Title="Print Preview" FontFamily="Calibri" FontSize="16">

  <Grid x:Name="LayoutRoot" Margin="2">
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
        <Border BorderThickness="0.5" BorderBrush="#666" Background="White">
            <ScrollViewer>
                <Image x:Name="previewImage" Stretch="Uniform" />
            </ScrollViewer>
            </Border>
        <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
    <Button x:Name="OKButton" Content="Print" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />     
    </Grid>
</sdk:ChildWindow>


 
public void ShowPreview(RichTextBox rtb)
{            
    WriteableBitmap image = new WriteableBitmap(rtb, null);
    previewImage.Source = image;            
}


当您在“打印预览”对话框中单击“确定”按钮时,将使用 PrintDocument 对象打印其内容,如下面的代码所示。

 
//Print the document
private void btnPrint_Click(object sender, RoutedEventArgs e)
{
    PrintPreview cw = new PrintPreview();
    cw.ShowPreview(rtb);
    cw.HasCloseButton = false;

    //Hook up a handler to the Closed event before displaying the PrintPreview window by calling the Show() method.
    cw.Closed += (t, a) =>
    {
        if (cw.DialogResult.Value)
        {
            PrintDocument theDoc = new PrintDocument();
            theDoc.PrintPage += (s, args) =>
            {
                args.PageVisual = rtb;
                args.HasMorePages = false;
            };

            theDoc.EndPrint += (s, args) =>
            {
                MessageBox.Show("The document printed successfully", "Text Editor", MessageBoxButton.OK);
            };

            theDoc.Print("Silverlight 4 Text Editor");
            ReturnFocus();
        }
    };
    cw.Show();
}


有关在 Silverlight 中进行打印的更多信息,请参见打印

Display

Silverlight 文本编辑器示例支持从右到左布局,这是 Silverlight 4 中的一项新功能。这是为了支持阿拉伯语和希伯来语等语言。下图显示了 Silverlight 文本编辑器示例的从右到左布局。

从右到左布局

可以使用“文本方向”切换按钮在从左到右布局和从右到左布局之间进行切换。下面的代码演示如何使用 FlowDirection 对象来实现切换。

 
//Set the flow direction
public void btnRTL_Checked(object sender, RoutedEventArgs e)
{
    //Set the button image based on the state of the toggle button. 
    if(btnRTL.IsChecked.Value)
        btnRTL.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/rtl.png", UriKind.RelativeOrAbsolute), 30, 32);
    else
        btnRTL.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/ltr.png", UriKind.RelativeOrAbsolute), 30, 32);

    ApplicationBorder.FlowDirection = (ApplicationBorder.FlowDirection == System.Windows.FlowDirection.LeftToRight) ? System.Windows.FlowDirection.RightToLeft : System.Windows.FlowDirection.LeftToRight;
    ReturnFocus();

}


 

可以使用“编辑/查看模式”切换按钮在编辑器的编辑状态和只读状态之间进行切换。默认情况下,编辑器处于编辑模式。下面的代码演示如何实现编辑/只读模式。

 
//Make the RichTextBox read-only
public void btnRO_Checked(object sender, RoutedEventArgs e)
{
    rtb.IsReadOnly = !rtb.IsReadOnly;

    //Set the button image based on the state of the toggle button.
    if (rtb.IsReadOnly)
        btnRO.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/view.png", UriKind.RelativeOrAbsolute), 29, 32);
    else
        btnRO.Content = MainPage.createImageFromUri(new Uri("/RichNotepad;component/images/edit.png", UriKind.RelativeOrAbsolute), 29, 32);
    ReturnFocus();
}


通过将 RichTextBox  IsReadOnly 属性设置为 true,指定只读模式。RichTextBox 中的 UI 元素和超链接仅在只读模式下处于活动状态。例如,UI 元素可以仅在它们处于只读模式时响应输入和接收焦点。有关 RichTextBox 的只读模式的更多信息,请参见 RichTextBox 概述

突出显示

“突出显示”切换按钮处于选中状态时,鼠标指针所悬停的整行将突出显示。下图显示突出显示的一个示例。

突出显示

下面的代码演示如何通过使用 TextPointer 类来实现突出显示。

 
public void btnHighlight_Checked(object sender, RoutedEventArgs e)
{
    if (btnHighlight.IsChecked.Value)
    {
        TextPointer tp = rtb.ContentStart;
        TextPointer nextTp = null;
        Rect nextRect = Rect.Empty;
        Rect tpRect = tp.GetCharacterRect(LogicalDirection.Forward);
        Rect lineRect = Rect.Empty;

        int lineCount = 1;

        while (tp != null)
        {
            nextTp = tp.GetNextInsertionPosition(LogicalDirection.Forward);
            if (nextTp != null && nextTp.IsAtInsertionPosition)
            {
                nextRect = nextTp.GetCharacterRect(LogicalDirection.Forward);
                // this occurs for more than one line
                if (nextRect.Top > tpRect.Top)
                {
                    if (m_selectionRect.Count < lineCount)
                        m_selectionRect.Add(lineRect);
                    else
                        m_selectionRect[lineCount - 1] = lineRect;

                    lineCount++;

                    if (m_selectionRect.Count < lineCount)
                        m_selectionRect.Add(nextRect);

                    lineRect = nextRect;
                }
                else if (nextRect != Rect.Empty)
                {
                    if (tpRect != Rect.Empty)
                        lineRect.Union(nextRect);
                    else
                        lineRect = nextRect;
                }
            }
            tp = nextTp;
            tpRect = nextRect;
        }
        if (lineRect != Rect.Empty)
        {
            if (m_selectionRect.Count < lineCount)
                m_selectionRect.Add(lineRect);
            else
                m_selectionRect[lineCount - 1] = lineRect;
        }
        while (m_selectionRect.Count > lineCount)
        {
            m_selectionRect.RemoveAt(m_selectionRect.Count - 1);
        }
    }
    else
    {
        if (highlightRect != null)
        {
            highlightRect.Visibility = System.Windows.Visibility.Collapsed;
        }
    }

}


当选中突出显示切换按钮时,事件处理程序将枚举 RichTextBox 的内容并构造围绕每行的矩形。矩形将添加到列表中。以下步骤说明如何创建所有矩形的列表。

  1. 获取一个 TextPointer 对象,该对象通过使用 ContentStart 属性指向 RichTextBox 内容的开头。

  2. 通过使用 GetCharacterRect 方法获取第一个字符的边框。

  3. 获取第一行的边框。这通过使用 GetNextInsertionPosition 方法枚举内容来实现。获取每个位置的 TextPointer 对象。通过比较使用行 TextPointer 的开头和当前 TextPointer获得的矩形的 Top 点坐标,检查您是否转到了下一行。在转到下一行的情况下,为当前行构造矩形,并将其添加到列表中,然后针对下一行启动相同枚举。

  4. 重复上一步骤,直到处理所有行。

现在,您具有与每一行内容相对应的矩形列表。

若要确定突出显示哪一行,代码对照 RichTextBox  MouseMove 事件处理程序中的矩形列表,针对当前鼠标位置执行命中测试。代码通过在名为 highlightCanvas  Canvas 上显示矩形来突出显示某行。

XAML

可以使用“XAML”按钮在编辑器中显示内容的 XAML 标记。RichTextBox.Xaml 属性用于实现此目的。下面的代码内容演示如何通过使用 Xaml 属性显示 XAML。

 
//Set the xamlTb TextBox with the current XAML of the RichTextBox and make it visible. Any changes to the XAML made 
//in xamlTb is also reflected back on the RichTextBox. Note that the Xaml string returned by RichTextBox.Xaml will 
//not include any UIElement contained in the current RichTextBox. Hence the UIElements will be lost when we 
//set the Xaml back again from the xamlTb to the RichTextBox.
public void btnMarkUp_Checked(object sender, RoutedEventArgs e)
{
    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;
    }

}


当您单击“XAML”按钮时,XAML 标记显示在名为 xamlTb  TextBox 中。默认情况下,xamlTb  Visibility 属性为 Collapsed;当您单击“XAML”按钮时将更改为 Visible。如果您对 xamlTb 中的 XAML 进行任何更改,所做更改都将反映在 RichTextBox 的内容中。请注意,Xaml 属性返回的 XAML 字符串将不包含 RichTextBox 中所包含的任何 UIElement 对象。因此,当您从 XAML 视图切换到 RichTextBox 时,UIElement 对象将丢失。

 

文件

当您单击“新建文件”按钮时,将清除 RichTextBox 中的现有内容。下面的代码显示用于创建新文件的过程。

 
//Clears the contents of the existing file.
private void btnNew_Click(object sender, RoutedEventArgs e)
{
    rtb.Blocks.Clear();
}


 

可以通过使用“打开文件”按钮打开现有文件。下面的代码显示用于打开现有文件的过程。

 
//Opens an existing file
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Multiselect = false;
    ofd.Filter = "Saved Files|*.sav|All Files|*.*";

    if (ofd.ShowDialog().Value)
    {
        FileInfo fi = ofd.File;
        StreamReader r = fi.OpenText();
        rtb.Xaml = r.ReadToEnd();
        r.Close();
    }
}


当您单击“打开文件”按钮时,将创建一个 OpenFileDialog 对象并通过使用 ShowDialog 方法显示此对象。这是标准的 Windows 打开文件对话框,您可用来选择要打开的文件。所选文件将作为 StreamReader 打开,其内容将分配给 RichTextBox  Xaml 属性。

 

可以通过使用“文件保存”按钮保存现有文件。如果 RichTextBox 包含任何 UIElement 对象,则保存操作将确实保存这些内容。您无法保存 UIElement 对象,因为 RichTextBox Xaml 属性只包含文本内容和关联的标记。下面的代码演示如何保存当前内容。

 
//Saves the existing file
private void btnSave_Click(object sender, RoutedEventArgs e)
{
    string ContentToSave = rtb.Xaml;

    //Check if the file contains any UIElements
    var res = from block in rtb.Blocks
              from inline in (block as Paragraph).Inlines
              where inline.GetType() == typeof(InlineUIContainer)
              select inline;

    //If the file contains any UIElements, it will not be saved
    if (res.Count() != 0)
    {
        MessageBox.Show("Saving documents with UIElements is not supported");
        return;
    }

    SaveFileDialog sfd = new SaveFileDialog();
    sfd.DefaultExt = ".sav";
    sfd.Filter = "Saved Files|*.sav|All Files|*.*";

    if (sfd.ShowDialog().Value)
    {
        using (FileStream fs = (FileStream)sfd.OpenFile())
        {
            System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
            byte[] buffer = enc.GetBytes(ContentToSave);
            fs.Write(buffer, 0, buffer.Length);
            fs.Close();
        }
    }
}


代码首先枚举 RichTextBox 的内容并检查是否存在任何 UIElement 对象。如果 RichTextBox 内容包含任何 UIElement 对象,则终止保存操作并显示消息框。如果 RichTextBox 只有文本元素,则将创建 SaveFileDialog 并使用 ShowDialog 方法显示它。这是标准的 Windows 保存文件对话框,您可用来保存文件。RichTextBox 中的内容将通过使用 Xaml 属性检索为一个字符串,然后写入到 FileStream 对象。

拖放

您可以通过将文本和 Office Word 文件拖到 Silverlight 文本编辑器示例中的内容区域来打开这些文件。此功能是通过使用 Silverlight 4 中的新拖放功能实现的。下面的代码演示拖放事件的事件处理程序方法。

 
private void rtb_Drop(object sender, System.Windows.DragEventArgs e)
{
    VisualStateManager.GoToState(this, "Normal", true);

    //the Drop event passes in an array of FileInfo objects for the list of files that were selected and drag-dropped onto the RichTextBox.
    if (e.Data == null)
    {
        ReturnFocus();
        return;
    }

    //This checks if the dropped objects are files and if not, return. 
    IDataObject f = e.Data as IDataObject;

    if (f == null)
    {
        ReturnFocus();
        return;
    }

    object data = f.GetData(DataFormats.FileDrop);
    FileInfo[] files = data as FileInfo[];

    if (files == null)
    {
        ReturnFocus();
        return;
    }

    //Walk through the list of FileInfo objects of the selected and drag-dropped files and parse the .txt and .docx files 
    //and insert their content in the RichTextBox.
    foreach (FileInfo file in files)
    {
        if (file == null)
        {
            continue;
        }

        if (file.Extension.Equals(".txt"))
        {
            ParseTextFile(file);
        }
        else if (file.Extension.Equals(".docx"))
        {
            ParseDocxFile(file);
        }
    }
    ReturnFocus();
}


 Drop 事件处理程序 (rtb_Drop) 中,在 RichTextBox 中删除的文件所对应的 FileInfo 对象的列表将传递到事件参数中。rtb_Drop 事件处理程序枚举 FileInfo 对象并分析 .txt 和 .docx 文件。将忽略带其他扩展名的文件。ParseTxtFile  ParseDocxFile 函数(本主题中未显示)采用 FileInfo 对象,对其进行分析,并将其内容添加到 RichTextBox