2017-01-14 36 views
1

我遇到RichTextBox控件的選擇問題。如果控件包含隱藏文本,則選擇的行爲會很奇怪。如果存在隱藏文本,WinForms RichTextBox選擇問題

  • 如果我用鼠標進行選擇,有時會出現錯誤,有時候不會。特別是如果我選擇更多的線,錯誤似乎消失。
  • 但是,如果用戶試圖用鍵盤來選擇文本,該錯誤是非常煩人的。

的問題是:比方說,我的控制有這樣的文字:

還有就是小升級控制,希望能做出 differnce當它被隱藏的文本的原因

然後讓我們說,我們通過運用恰當的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正在形成控件內的內容,並作爲隱藏文本存儲在特殊位置,而我不能/不想改變這一點)。

+0

你可以用乾淨的新項目重現問題嗎?我的意思是你可以爲這個問題創建一個[MCVE](http://stackoverflow.com/help/mcve)嗎? –

+0

是的,它似乎很容易重現。我不認爲這是我的代碼中的錯誤,而是富文本框控件的行爲,或者控件本身內部的錯誤。 [在這裏你可以找到示例項目的錯誤](https://www.dropbox.com/s/sef62c2c2kt2ds2/rtbTest.zip?dl=0) 只需點擊文本的開始(第一個文本框內)它已經包含隱藏的內容,按住Shift並按下左箭頭,就像通常使用鍵盤選擇文本一樣。 選擇將在到達隱藏字時重置 – aleksandaril

+0

您能否提供MCVE?我的意思是至少使用了RTF。只要檢查一下你是否可以用那個RTF的乾淨項目真正地複製它。 –

回答

0

我使用以下Form,其中richTextBox是有問題的RichTextBoxRichTextBox_SelectionChangedSelectionChanged 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; 
    } 
} 

IsKeyBoardSelection爲簡單起見可以像下面這樣,雖然正確檢測選擇更改源將更加困難:

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

FixSelection方法應該比較newSelection是否可以是this._previousSelection並創建一個新SelectionData那將包含newSelection,this._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處理(就像在FocusLost事件重置它) - 有一些邊緣情況下,但仍然沒有什麼不可能的。

    public MainForm() 
    { 
        ... 
        this.richTextBox.LostFocus += RichTextBox_LostFocus; 
    } 
    
    private void RichTextBox_LostFocus(object sender, EventArgs e) 
    { 
        this._previousSelection = null; 
    } 
    

PS:爲了簡單起見,我已經實現了一切與字段和表單級處理的形式內,但也有一些努力,也可以做成一些可重複使用的(在最壞的情況衍生RichTextBox,充其量一些外部部件將爲RichTextBox提供這種處理)。

+0

感謝您的回覆,並很抱歉在很長一段時間後將其標記爲已解決。這是我的問題的正確答案,但不幸的是,這不是我們問題的答案。我們不得不採取另一個方向,因爲我們有些微的變化。保持我們的數據隱藏在文本中是不可能的,也不允許有新的需求。 無論如何,這是一個有趣的問題,並感謝您的幫助。 – aleksandaril