2010-09-27 85 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); 
}