2010-09-27 4 views
4

У меня есть WinForms программа, где при изменении вашего выбора RichTextBox необходимо изменить цвет другого текста. Чтобы сделать это, он должен выбрать этот текст, и поэтому я теряю свой текущий выбор.RichTextBox Save "Selection Direction"

Я могу сохранить и загрузить свойства SelectionStart и SelectionLength, но я не могу сохранить «направление выбора»: если пользователь выделял вперед или назад курсор.

Любые идеи о том, как я могу либо сохранить направление выделения, либо покрасить текст, не меняя выделение?

+0

Было ли это разрешено вообще? Со своей стороны, я попытался отправить нажатия клавиш «Shift-Left» и «Shift-Right» в быстрой последовательности, чтобы определить, каким образом карет перемещается и определяет «направление», но проблема с использованием нажатий клавиш заключается в том, что другая логика, прикрепленная к ключу события вызывают в результате. –

+0

Я не думаю, что когда-либо делал это, я думаю, что я использовал еще один предустановленный синтаксический контрольный элемент, который смог сделать это автоматически. – Miguel

ответ

1

Yuck, уродливая проблема. Нет, EM_SETPARAFORMAT может работать только с текущим выбором. И EM_EXSETSEL всегда ставит каретку в конце выбора. Вы можете определить направление выбора, наблюдая изменение в SelectionStart, но вы не можете получить каретку в нужном месте. Аналогичная проблема имеет элемент управления редактирования.

Обычно это не проблема, потому что повторная раскраска происходит только тогда, когда пользователь изменяет текст, а не когда она выбирает текст. Единственным обходным решением, о котором я могу думать, является восстановление выбора путем ввода нажатий клавиш. Это глупо.

+0

Интересно, что произойдет, если вы использовали EM_EXSETSEL и имели cpMax как отрицательное число. – Miguel

0

Другой способ - напрямую установить свойство Rtf. Вам нужно знать синтаксис языка rtf.

PS. Это также отменяет выбор. Я сам сделал нажатие клавиши.

0

Я просто попал в ту же проблему, и теперь я решил это с помощью EM_EXSETSEL. Когда cpMin> cpMax, он работает как «обратный выбор» (каретка в начале выделенного текста). Тем не менее, я не нашел никакого другого способа узнать текущее направление выбора (EM_EXGETSEL всегда возвращается cpMin < cpMax), но следующие изменения SelectionStart/длина ...

EDIT:

Вот что я использую, чтобы решить это. Может быть, есть более простой способ, но по крайней мере для меня это работает.

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); 
}