动态样式RichTextBox中的文本子字符串

时间:2016-10-17 18:31:33

标签: c# wpf styling textblock

所以,我有一个WPF RichTextBox,它将绑定一长串文本。

我想要做的是使用一组两个TextPointer对象,以便在任何给定时间,两个指针之间的文本都应用了一个样式。 (例如,在用户移动选择时更改文本的背景/前景色。)一旦文本不再在两个指针之间,样式必须重置为原始样式。

例如,您可以单击并拖动以突出显示/选择网站上的文本的方式与所需行为类似(但不相同)。而不是单击和拖动(用户不应该这样做,我将以编程方式确定端点。)

我似乎无法找到办法。我知道我可以将所需的样式应用于<Run></Run>,但我无法弄清楚如何从控件中获取文本的某个子字符串并应用(以及删除)Run以编程方式标记它。

理想的解决方案是更改select方法应用的样式。我有点担心这样做(如果它甚至可以完成)因为我不确定是否可以禁用用户的选择(不禁用鼠标)并且仍然可以使用程序选择。

1 个答案:

答案 0 :(得分:1)

更新:我认为您最初谈论的是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"
        />