2010-09-27 89 views
4

我有一個WinForms程序其中,無論何時更改您的選擇,RichTextBox都需要更改某些其他文本的顏色。爲了做到這一點,它必須選擇文本,因此我失去了我目前的選擇。RichTextBox保存「選擇方向」

我可以保存並加載SelectionStart和SelectionLength屬性,但我無法保留「選擇方向」:如果用戶從光標向前或向後突出顯示。

有關如何保存選擇方向或爲文本上色而不必更改選區的任何想法?

+0

這個問題解決了嗎?就我而言,我試着快速連續地發送「Shift-Left」和「Shift-Right」的擊鍵以確定插入符號移動並確定「方向」的方式,但使用擊鍵的問題在於其他邏輯連接到鍵事件被調用爲結果。 – 2012-04-04 21:57:59

+0

我不認爲我曾經這樣做過,我想我只是使用了另一種預編譯語法來突出顯示能夠自動執行的控件。 – Miguel 2012-05-08 10:24:18

回答

1

Yu,,醜陋的問題。不,EM_SETPARAFORMAT只能用於當前選擇。 EM_EXSETSEL總是將插入符號放在選擇的末尾。您可以通過觀察SelectionStart中的更改來檢測選擇方向,但是無法在正確的位置獲取插入符號。編輯控件有同樣的問題。

這通常不是問題,因爲重新着色只在用戶修改文本時發生,而不是在她選擇文本時發生。我能想到的唯一解決方法是通過注入擊鍵恢復選擇。真讓人難過。

+0

我想知道如果您使用EM_EXSETSEL並將cpMax作爲負數會發生什麼情況。 – Miguel 2010-09-27 08:14:52

0

另一種方法可以直接設置Rtf屬性。你確實需要知道rtf語言的語法。

PS。這也會使選擇無效。我自己做了按鍵注射。

0

我剛剛遇到同樣的問題,現在我通過使用EM_EXSETSEL解決了這個問題。當cpMin> cpMax時,它就像「向後選擇」(選定文本的開頭處的插入符號)一樣工作。然而,我還沒有發現任何其他方式找出當前選擇方向(EM_EXGETSEL總是返回cpMin < cpMax則),但以下SelectionStart /長度變化......

編輯:

這是我使用的解決一下這個。可能有一些更簡單的方法,但至少以下適用於我。

using System.Runtime.InteropServices; 

//******************** 
//SendMessage stuff for EM_EXSETSEL 
//******************** 

[StructLayout(LayoutKind.Sequential)] 
public struct CHARRANGE 
{ 
    public int cpMin; 
    public int cpMax; 
} 

[DllImport("user32.dll")] 
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref CHARRANGE lParam); 

private const UInt32 WM_USER = 0x0400; 
private const UInt32 EM_EXSETSEL = WM_USER + 55; 
private const UInt32 EM_EXGETSEL = WM_USER + 52; 

//******************** 
//event handlers 
//******************** 

//locking variable to avoid stack overflow while setting selection in code 
private bool richTextBox1_SelectionChanged_lock = false; 

//handler for richTextBox selection change event 
private void richTextBox1_SelectionChanged(object sender, EventArgs e) 
{ 
    if (richTextBox1_SelectionChanged_lock) return; 
    richTextBox1_SelectionChanged_lock = true; 

    //detect selection changes and store information needed for restoring 
    TrackRTBSelection(richTextBox1.SelectionStart, richTextBox1.SelectionLength); 

    //here do whatever you want with selection (some analysis to show font name in font selection comboBox etc.) 
    //... 

    //restore selection from saved informations 
    SetRTBSelectionBasedOnTracking(); 

    richTextBox1_SelectionChanged_lock = false; 
} 

//sample button click handler for changing fore color of selected text 
private void buttonSetForeColor_Click(object sender, EventArgs e) 
{ 
    if (colorDialog1.ShowDialog() == DialogResult.Cancel) 
     return; 

    //prevent selection change events while we are changing font colors 
    if (richTextBox1_SelectionChanged_lock) return; 
    richTextBox1_SelectionChanged_lock = true; 

    //save selection parameters for use in loop 
    int selStart = richTextBox1.SelectionStart; 
    int selLength = richTextBox1.SelectionLength; 

    for (int i = 0; i < selLength; i++) 
    { 
     richTextBox1.SelectionLength = 1; 
     richTextBox1.SelectionStart = selStart + i; 

     richTextBox1.SelectionColor = colorDialog1.Color; 
    } 

    //restore selection from saved informations 
    SetRTBSelectionBasedOnTracking(); 

    richTextBox1_SelectionChanged_lock = false; 
} 

//******************** 
//selection tracking utilities 
//******************** 

//false - caret at the beginning; true - caret at the end 
private bool caretPosition = false; 
private int lastSelectionStart = -1; 
private int lastSelectionLength = -1; 

//initialize selection informations. this must be called during Form_Load 
private void InitRTBSelection() 
{ 
    richTextBox1.SelectionStart = 0; 
    richTextBox1.SelectionLength = 0; 

    caretPosition = false; 
    lastSelectionStart = 0; 
    lastSelectionLength = 0; 

    //force "selection changed" to detect "selection changes" for the first time 
    richTextBox1_SelectionChanged(richTextBox1, new EventArgs()); 
} 

//this method detects changes in selection, based on selection parameters received from richTextBox 
private void TrackRTBSelection(int newSelectionStart, int newSelectionLength) 
{ 
    int condition = 0; 

    int s_change = (newSelectionStart - lastSelectionStart > 0) ? 
        1 : 
        (newSelectionStart - lastSelectionStart < 0) ? -1 : 0; 
    int l_change = (newSelectionLength - lastSelectionLength > 0) ? 
        1 : 
        (newSelectionLength - lastSelectionLength < 0) ? -1 : 0; 

    //these conditions where created over change table for all user-achievable scenarios 
    condition = (newSelectionLength == 0 || 
       (l_change == 1 && s_change == -1) || 
       (l_change == -1 && s_change == 1 && caretPosition == false)) ? 1 : condition; 
    condition = (s_change == 0 && (l_change == 1 || (caretPosition == true && l_change == -1))) ? 2 : condition; 

    switch (condition) 
    { 
     case 1: caretPosition = false; break; 
     case 2: caretPosition = true; break; 
     default: break; //if no condition was satisfied then maintain current information 
    } 

    lastSelectionStart = newSelectionStart; 
    lastSelectionLength = newSelectionLength; 
} 

//set richTextBox selection using EM_EXSETSEL 
private void SetRTBSelectionBasedOnTracking() 
{ 
    CHARRANGE chrrange = new CHARRANGE 
    { 
     cpMin = caretPosition ? lastSelectionStart : lastSelectionStart + lastSelectionLength, 
     cpMax = caretPosition ? lastSelectionStart + lastSelectionLength : lastSelectionStart 
    }; 
    SendMessage(richTextBox1.Handle, EM_EXSETSEL, IntPtr.Zero, ref chrrange); 
}