2016-10-17 6 views
0

Итак, у меня есть WPF RichTextBox, который будет привязан к длинной строке текста.Динамическая подстрока текста в RichTextBox

Что я хочу сделать, это использовать набор из двух объектов TextPointer, так что в любой момент времени текст между двумя указателями имеет стиль, применяемый к нему. (Например, измените цвет фона/переднего плана текста.), Когда пользователь перемещает выбор. Как только текст больше не находится между двумя указателями, стиль должен быть сброшен до исходного стиля.

Желаемое поведение похоже на (хотя и не такое же), как вы можете щелкнуть и перетащить, чтобы выделить/выбрать текст на веб-сайте, например. Вместо того, чтобы щелкать и перетаскивать (пользователь НЕ должен этого делать, я буду программно определять конечные точки.)

Я не могу понять, как это сделать. Я знаю, что я могу применить необходимые стили к <Run></Run>, но я не могу понять, как получить определенную подстроку текста из элемента управления и применить (а также удалить) теги Run к нему программно.

Идеальным решением было бы изменить стиль, применяемый методом select. Я немного опасаюсь сделать это (если это даже можно сделать), поскольку я не уверен, что можно отключить выбор пользователя (без отключения мыши), и у меня все еще есть программный выбор.

+0

пытаются объяснить с изображением. перемещение выделенного текста уже доступно в RTB. – AnjumSKhan

ответ

1

UPDATE: Я думаю, вы изначально говорили о TextBlock, а не о RichTextBox. Если для решения абсолютно требуется RichTextBox, вам нужно будет найти полезный парсер RTF где-нибудь.

Одна вещь, которую вы можете сделать, это использовать элементы управления RTF или HTML.

Или вы могли бы использовать приведенный ниже код, который я написал с пистолетом в голову (на самом деле, я написал его, чтобы посмотреть, смогу ли я). Это, возможно, грех против MVVM, но вы можете закрыть глаза и притвориться, что теги <Bold> и т. Д. - это всего лишь какой-то произвольный язык разметки, а не XAML.

Во всяком случае: когда желаемый диапазон для форматирования изменяется, обновите свойство FormattedText и поднимите PropertyChanged.

C#

namespace HollowEarth.AttachedProperties 
{ 
    public static class TextProperties 
    { 
     #region TextProperties.XAMLText Attached Property 
     public static String GetXAMLText(TextBlock obj) 
     { 
      return (String)obj.GetValue(XAMLTextProperty); 
     } 

     public static void SetXAMLText(TextBlock obj, String value) 
     { 
      obj.SetValue(XAMLTextProperty, value); 
     } 

     /// <summary> 
     /// Convert raw string into formatted text in a TextBlock: 
     /// 
     /// @"This <Bold>is a test <Italic>of the</Italic></Bold> text." 
     /// 
     /// Text will be parsed as XAML TextBlock content. 
     /// 
     /// See WPF TextBlock documentation for full formatting. It supports spans and all kinds of things. 
     /// 
     /// </summary> 
     public static readonly DependencyProperty XAMLTextProperty = 
      DependencyProperty.RegisterAttached("XAMLText", typeof(String), typeof(TextProperties), 
               new PropertyMetadata("", XAMLText_PropertyChanged)); 

     // I don't recall why this was necessary; maybe it wasn't. 
     public static Stream GetStream(String s) 
     { 
      MemoryStream stream = new MemoryStream(); 
      StreamWriter writer = new StreamWriter(stream); 

      writer.Write(s); 
      writer.Flush(); 
      stream.Position = 0; 

      return stream; 
     } 

     private static void XAMLText_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      if (d is TextBlock) 
      { 
       var ctl = d as TextBlock; 

       try 
       { 
        // XAML needs a containing tag with a default namespace. We're parsing 
        // TextBlock content, so make the parent a TextBlock to keep the schema happy. 
        // TODO: If you want any content not in the default schema, you're out of luck. 
        var strText = String.Format(@"<TextBlock xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">{0}</TextBlock>", e.NewValue); 

        TextBlock parsedContent = System.Windows.Markup.XamlReader.Load(GetStream(strText)) as TextBlock; 

        // The Inlines collection contains the structured XAML content of a TextBlock 
        ctl.Inlines.Clear(); 

        // UI elements are removed from the source collection when the new parent 
        // acquires them, so pass in a copy of the collection to iterate over. 
        ctl.Inlines.AddRange(parsedContent.Inlines.ToList()); 
       } 
       catch (Exception ex) 
       { 
        System.Diagnostics.Trace.WriteLine(String.Format("Error in HollowEarth.AttachedProperties.TextProperties.XAMLText_PropertyChanged: {0}", ex.Message)); 
        throw; 
       } 
      } 
     } 
     #endregion TextProperties.XAMLText Attached Property 
    } 
} 

Другое C#

// This `SpanStyle` resource is in scope for the `TextBlock` I attached 
// the property to. This works for me with a number of properties, but 
// it's not changing the foreground. If I apply the same style conventionally 
// to a Span in the real XAML, the foreground color is set. Very curious. 
// StaticResource threw an exception for me. I couldn't figure out what to give 
// XamlReader.Load for a ParserContext. 
FormattedText = "Text <Span Style=\"{DynamicResource SpanStyle}\">Span Text</Span>"; 

XAML

<TextBlock 
     xmlns:heap="clr-namespace:HollowEarth.AttachedProperties" 
     heap:TextProperties.XAMLText="{Binding FormattedText}" 
     /> 

    <TextBlock 
     xmlns:heap="clr-namespace:HollowEarth.AttachedProperties" 
     heap:TextProperties.XAMLText="This is &lt;Italic Foreground=&quot;Red&quot;&gt;italic and &lt;Bold&gt;bolded&lt;/Bold&gt;&lt;/Italic&gt; text" 
     /> 
+0

Да, я понял, что, по сути, я спрашиваю, как превратить «TextBlock» в «RichTextBox». Я отредактировал свой вопрос, чтобы уважать здравомыслие. – Airhead

+1

@ Прикосновение Эйрхеда переоценено. Мой ответ делает это с помощью «TextBlock». –