如果存在隐藏文本

时间:2017-01-14 11:12:27

标签: c# winforms selection richtextbox hidden

我有RichTextBox控件的选择问题。如果控件包含隐藏文本,则选择行为奇怪。

  • 如果我使用鼠标进行选择,有时会出现错误,有时则不存在。特别是如果我选择更多行,那么这个bug似乎就会消失。
  • 但如果用户尝试使用键盘选择文字,则该错误非常烦人。

问题如下:假设我的控件有这样的文字:

  

有一个很小的升级控制,希望能成为一个   隐藏文字的原因是什么

然后假设我们通过应用正确的RTF标记来隐藏单词upgraded, hopefully, hidden

@"{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fni‌​l\fcharset0 Microsoft Sans Serif;}} \viewkind4\uc1\pard\f0\fs17 There is the little \v upgraded \v0 control that \v hopefully \v0 will make a differnce when it is \v hidden \v0 text the reason\par}";

一切看起来都不错,但是当用户尝试使用键盘选择文本时,每次到达隐藏单词时,选择似乎都会重置。

对于我的控件来说,包含隐藏文本是至关重要的(来自控件内部形成内容的对象的一些重要id被存储为特殊位置的隐藏文本,我不能/不想改变这一点)。

1 个答案:

答案 0 :(得分:0)

我正在使用以下Form,其中richTextBox是有问题的RichTextBoxRichTextBox_SelectionChanged是我们将尝试使用的SelectionChanged event处理程序解决我们的问题。

public MainForm()
{
    InitializeComponent();

    this.richTextBox.Rtf =
        @"{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fni‌​l\fcharset0 Microsoft Sans Serif;}}\viewkind4\uc1\pard\f0\fs17 My \v upgraded \v0 control that \v hopefully \v0 will make it\par}";            
    this.richTextBox.SelectionChanged += RichTextBox_SelectionChanged;
}

基本上,这个想法很简单 - 使用SelectionChanged处理程序正确Select隐藏数据与之前的选择一起。

为此,我们必须存储以前的选择数据:

private class SelectionData
{
    public static SelectionData FromStartAndEnd(
        Int32 start,
        Int32 end)
    {
        return new SelectionData(
            start: start,
            length: end - start);
    }

    public SelectionData(TextBoxBase tb)
        : this(
            start: tb.SelectionStart,
            length: tb.SelectionLength)
    {            }

    public SelectionData(Int32 start, Int32 length)
    {
        this.Start = start;
        this.Length = length;
    }

    public readonly Int32 Start, Length;
    public Int32 End
    {
        get
        {
            return this.Start + this.Length;
        }
    }
}

在某些领域:

private SelectionData _previousSelection;

SelectionChanged hanlder

中更新/修复选择
private void RichTextBox_SelectionChanged(object sender, EventArgs e)
{
    var newSelection = new SelectionData(this.richTextBox);
    this.SelfUpdateSelection(newSelection);
}

SelfUpdateSelection方法类似于:

private Boolean _isSelectionSelfUpdating = false;

private void SelfUpdateSelection(SelectionData newSelection)
{
    if (!this.IsKeyBoardSelection())
    {
        // Or it will use previous selection when we don't need it.
        this._previousSelection = null; 
        return;
    }
    if (this._isSelectionSelfUpdating)
        return;

    this._isSelectionSelfUpdating = true;
    try
    {
        var fixedSelection = this.FixSelection(newSelection);
        this.richTextBox.Select(
            start: fixedSelection.Start,
            length: fixedSelection.Length);
        this._previousSelection = fixedSelection;
    }
    finally
    {
        this._isSelectionSelfUpdating = false;
    }
}
为简单起见,{p> IsKeyBoardSelection可能类似于以下内容,但正确检测选择更改源将更加困难:

private bool IsKeyBoardSelection()
{
    // It may not be true, but usually close enough.
    return Control.ModifierKeys.HasFlag(Keys.Shift);
}

FixSelection方法应比较newSelection是否为this._previousSelection并创建包含SelectionDatanewSelectionthis._previousSelection的新private SelectionData FixSelection(SelectionData newSelection) { if (this._previousSelection == null) return newSelection; var start = Math.Min( newSelection.Start, this._previousSelection.Start); var end = Math.Max( newSelection.End, this._previousSelection.End); return SelectionData.FromStartAndEnd( start: start, end: end); } 它们之间的隐藏数据。

您可以使用以下内容:

FixSelection

但它:

  • 仅适用于前进(右箭头)选择 - 可以通过向this._previousSelection添加一些额外的逻辑来修复。
  • 还需要一些额外的public MainForm() { ... this.richTextBox.LostFocus += RichTextBox_LostFocus; } private void RichTextBox_LostFocus(object sender, EventArgs e) { this._previousSelection = null; } 处理(比如在FocusLost事件中重置它) - 有一些边缘情况,但仍然没有什么不可能。

    RichTextBox

PS:为了简单起见,我已经使用字段和表单级处理程序在表单中实现了所有内容,但是通过一些努力,它可以被制作成可重用的东西(最坏的派生RichTextBox,最好是一些外部组件,它将为manifestPlaceholders)提供这样的处理。