【问题标题】:Dynamically style substring of text within a RichTextBox动态设置 RichTextBox 中文本的子字符串样式
【发布时间】:2017-02-26 20:16:47
【问题描述】:

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

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

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

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

理想的解决方案是更改 select 方法应用的样式。我对此有点谨慎(如果可以做到的话),因为我不确定是否可以禁用用户的选择(不禁用鼠标)并且仍然可以使用编程选择。

【问题讨论】:

  • 尝试用图片来解释。 RTB 中已经可以移动选定的文本。

标签: c# wpf styling textblock


【解决方案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"
        />

【讨论】:

  • 是的,我意识到我实际上是在问如何将TextBlock 变成RichTextBox。我已经相应地编辑了我的问题以尊重理智。
  • @Airhead 理智被高估了。我的回答是TextBlock
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-17
  • 2023-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-15
相关资源
最近更新 更多