2010-09-27 24 views
4

J'ai un programme WinForms où, chaque fois que vous modifiez votre sélection, la RichTextBox doit modifier la couleur de certains autres textes. Pour ce faire, il doit sélectionner ce texte, et donc je perds ma sélection actuelle.RichTextBox Enregistrer "Direction de la sélection"

Je peux enregistrer et charger les propriétés SelectionStart et SelectionLength, mais je ne peux pas conserver la «direction de sélection»: si l'utilisateur mettait en surbrillance le curseur vers l'avant ou vers l'arrière.

Des idées sur la façon dont je peux enregistrer la direction de la sélection, ou colorier le texte sans avoir à changer la sélection?

+0

Est-ce que cela a été résolu? Pour ma part, j'ai essayé d'envoyer rapidement des touches pour "Shift-Left" et "Shift-Right" pour déterminer la direction du mouvement et déterminer la "direction", mais le problème avec l'utilisation des touches est cette autre logique les événements sont appelés comme résultat. –

+0

Je ne pense pas que je l'ai jamais fait, je pense que je viens d'utiliser un autre contrôle de mise en évidence syntaxique préconstruit qui était capable de le faire automatiquement. – Miguel

Répondre

1

Yuck, problème moche. Non, EM_SETPARAFORMAT ne peut fonctionner que sur la sélection en cours. Et EM_EXSETSEL met toujours le curseur à la fin de la sélection. Vous pouvez détecter la direction de sélection en observant le changement dans SelectionStart mais vous ne pouvez pas obtenir le curseur au bon endroit. Un contrôle d'édition a le même problème.

Ce n'est normalement pas un problème car la retouche ne se produit que lorsque l'utilisateur modifie le texte, et non lorsqu'il sélectionne du texte. La seule solution de rechange que je peux penser est de restaurer la sélection en injectant des frappes. C'est fugement.

+0

Je me demande ce qui se passerait si vous utilisiez EM_EXSETSEL et que cpMax était un nombre négatif. – Miguel

0

Une autre méthode peut être de définir directement la propriété Rtf. Vous avez besoin de connaître la syntaxe du langage rtf.

PS. Cela invalidera également la sélection. J'ai fait l'injection de frappe moi-même.

0

Je viens de frapper le même problème et maintenant j'ai résolu cela en utilisant EM_EXSETSEL. Quand cpMin> cpMax, cela fonctionne comme "sélection vers l'arrière" (caret au début du texte sélectionné). Pourtant, je ne l'ai pas trouvé d'autre moyen de savoir la direction de la sélection actuelle (EM_EXGETSEL toujours retourné CPmin < CPmax), mais suite à des changements SelectionStart/longueur ...

EDIT:

C'est ce que j'utilise pour résoudre ce. Il pourrait y avoir un moyen plus facile, mais au moins les travaux suivants pour moi.

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