WPF RichTextBox中的只读运行元素?

WPF RichTextBox中的只读运行元素?,wpf,xaml,richtextbox,.net-3.5,Wpf,Xaml,Richtextbox,.net 3.5,我可能完全在想象这一点,但我可以发誓有一种方法可以使RichTextBox中的单个Run(或paragraph)元素只读。我还可以发誓,几周前我自己也尝试过一种方法来解决这个问题,并且对结果感到满意——我隐约记得它看起来像这样: <RichTextBox x:Name="richTextBox" AcceptsTab="True" AcceptsReturn="True" FontFamily="Courier

我可能完全在想象这一点,但我可以发誓有一种方法可以使RichTextBox中的单个Run(或paragraph)元素只读。我还可以发誓,几周前我自己也尝试过一种方法来解决这个问题,并且对结果感到满意——我隐约记得它看起来像这样:

<RichTextBox x:Name="richTextBox"
             AcceptsTab="True"
             AcceptsReturn="True"
             FontFamily="Courier New"
             FontSize="14">
    <FlowDocument>
        <Paragraph>
            <Run IsReadOnly="True">I wish this was read-only!</Run>
        </Paragraph>
    </FlowDocument>
</RichTextBox>

我希望这是只读的!
现在,几周后,我尝试在RichTextBox中将Run元素设置为只读,结果发现这似乎是不可能的

似乎证实了这一点


我完全想象到了吗?或者有什么方法可以做我想做的吗?

好吧,我想出了一个适合我的解决方案——但可能不适合所有想要这样做的人。它很凌乱,但它能起作用

我不会在几天内接受我自己的答案,以防万一其他人有更好的方法来实现这一点

我们开始吧,首先是XAML:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1"
        Height="500"
        Width="600">
    <DockPanel LastChildFill="True">
        <RichTextBox x:Name="rtb"
                     FontFamily="Courier New"
                     FontSize="14"
                     PreviewKeyDown="rtb_PreviewKeyDown">
            <FlowDocument>
                <Paragraph>
                    <InlineUIContainer Unloaded="InlineUIContainer_Unloaded">
                        <TextBlock FontFamily="Courier New" FontSize="14">This line of text is not editable.</TextBlock>
                    </InlineUIContainer>
                    <Run Foreground="Blue">But this is editable.</Run>
                </Paragraph>
            </FlowDocument>
        </RichTextBox>
    </DockPanel>
</Window>
我的解决方案依赖于这样一个事实:当从UI中删除
InlineUIContainer
时,调用
unload()
方法。此时,我只需在当前插入符号位置重新插入已删除的
InlineUIContainer

与任何黑客一样,它也有许多缺点。我发现的缺点如下:

  • 我想要只读的文本需要包装在
    InlineUIContainer
    中。这对这个解决方案有点限制
  • 我必须捕获“回车”键并手动插入换行符,否则,
    InlineUIContainer.unload()
    每次按下回车键时都会持续触发。不好玩,但对我的案子来说很管用

这不是一个很好的解决方案,但我认为它会对我有用。正如我所说,我现在还不打算把它作为我自己问题的答案——希望其他人有更好的方法来解决这个问题。

这可以通过处理两个事件来实现:1)OnMouseDown 2)OnPreviewKeyDown

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;

namespace WpfApplication2
{
public class MultiPartTextBox : TextBox
{
    private string _prefix;
    private string _content;

    public string Prefix
    {
        get { return _prefix; }
        set { _prefix = value;
        Text = _prefix;
        }
    }

    public string Content
    {
        get { return _content; }
        set { 
            _content = value;
            Text = _prefix + _content;
        }
    }

    public MultiPartTextBox() { _prefix = string.Empty; }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {

        base.OnMouseDown(e);
        this.SelectionStart = _prefix.Length;
        this.SelectionLength = 0;
    }

    //tab In
    protected override void OnGotFocus(RoutedEventArgs e)
    {
        this.SelectionStart = _prefix.Length;
        this.SelectionLength = 0;
        base.OnGotFocus(e);
    }

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        if (e.Key == Key.Back 
            || e.Key == Key.Delete
            || e.Key==Key.Left)
        {
            if (CaretIndex <= _prefix.Length)
            {
                e.Handled = true;
                return;
            }
        }
        base.OnPreviewKeyDown(e);
    }
  }
  }
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows.Controls;
使用System.Windows;
使用System.Windows.Input;
命名空间WpfApplication2
{
公共类MultiPartTextBox:TextBox
{
私有字符串前缀;
私有字符串\u内容;
公共字符串前缀
{
获取{return\u prefix;}
设置{u前缀=值;
Text=_前缀;
}
}
公共字符串内容
{
获取{return\u content;}
集合{
_内容=价值;
文本=_前缀+_内容;
}
}
public MultiPartTextBox(){u prefix=string.Empty;}
MouseDown上的受保护覆盖无效(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
this.SelectionStart=\u prefix.Length;
this.SelectionLength=0;
}
//插页
受保护的覆盖无效OnGotFocus(路由目标e)
{
this.SelectionStart=\u prefix.Length;
this.SelectionLength=0;
基地,昂戈特福克斯(e);;
}
PreviewKeyDown(KeyEventArgs e)上受保护的覆盖无效
{
如果(e.Key==Key.Back
||e.Key==Key.Delete
||e.Key==Key.Left)
{

if(CaretIndex)非常有趣,如果您愿意,它将帮助我将“小部件”添加到文本编辑器中。我正在制作一个非常好的窗口,如Wiki编辑器。因此,对于添加图像、类别和关键字,我使用小对象装饰富文本对象。我希望编辑器更像visual studio编辑器。这样我可以添加“装饰”但是…这确实帮了我的忙!谢谢。很高兴它能帮上忙-尽管有警告-我隐约记得可以用退格键删除只读文本。我不确定这么久之后,但我会彻底测试它,以确保小部件保持只读。你忘了触摸手指了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;

namespace WpfApplication2
{
public class MultiPartTextBox : TextBox
{
    private string _prefix;
    private string _content;

    public string Prefix
    {
        get { return _prefix; }
        set { _prefix = value;
        Text = _prefix;
        }
    }

    public string Content
    {
        get { return _content; }
        set { 
            _content = value;
            Text = _prefix + _content;
        }
    }

    public MultiPartTextBox() { _prefix = string.Empty; }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {

        base.OnMouseDown(e);
        this.SelectionStart = _prefix.Length;
        this.SelectionLength = 0;
    }

    //tab In
    protected override void OnGotFocus(RoutedEventArgs e)
    {
        this.SelectionStart = _prefix.Length;
        this.SelectionLength = 0;
        base.OnGotFocus(e);
    }

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        if (e.Key == Key.Back 
            || e.Key == Key.Delete
            || e.Key==Key.Left)
        {
            if (CaretIndex <= _prefix.Length)
            {
                e.Handled = true;
                return;
            }
        }
        base.OnPreviewKeyDown(e);
    }
  }
  }
   xmlns:uc="clr-namespace:WpfApplication2"

       <uc:MultiPartTextBox Height="30" HorizontalAlignment="Left" 
             Margin="80,94,0,0" x:Name="multiPartTxt1" VerticalAlignment="Top" 
             Width="224" Prefix="NON-EDITABLE" CaretIndex="4" >            
       </uc:MultiPartTextBox>