2009-05-27 15 views
1

J'ai une TreeView et une zone de texte multiligne ensemble sur le même formulaire dans un formulaire Windows. J'ai glisser et déposez l'installation de sorte que je puisse faire glisser un noeud de la TreeView sur la zone de texte et insérer du texte dans la zone de texte (cela fonctionne).Comment faire pour déplacer insert insertion sur la zone de texte lors de l'acceptation d'une suppression

Je voudrais améliorer cela de sorte que lorsque la souris est déplacée sur la zone de texte, une sorte d'indicateur se déplace dans le texte montrant l'utilisateur où le texte sera inséré, et lorsqu'il est déposé, il est inséré à cette position. Actuellement, je viens de mettre le texte à SelectionStart, mais l'opération de glisser ne met pas à jour SelectionStart donc c'est là où l'utilisateur a eu le curseur en dernier.

Voici mon code actuel:

private void treeView1_ItemDrag(object sender, ItemDragEventArgs e) 
    { 
     if (e.Button != MouseButtons.Left) 
      return; 

     object item = e.Item; 
     treeView1.DoDragDrop(((TreeNode)item).Tag.ToString(), DragDropEffects.Copy | DragDropEffects.Scroll); 
    } 

    private void textBox1_DragEnter(object sender, DragEventArgs e) 
    { 
     if (e.Data.GetDataPresent(DataFormats.StringFormat)) 
     { 
      e.Effect = DragDropEffects.Copy | DragDropEffects.Scroll; 
     } 
     else 
     { 
      e.Effect = DragDropEffects.None; 
     } 
    } 

    private void textBox1_DragDrop(object sender, DragEventArgs e) 
    { 
     if (e.Data.GetDataPresent(DataFormats.StringFormat)) 
     { 
      textBox1.SelectionLength = 0; 
      textBox1.SelectedText = (string)e.Data.GetData(DataFormats.StringFormat); 
     } 
    } 
+0

C'est ce que je cherchais. Merci! –

Répondre

3

Je pense que vous aurez envie de regarder traiter l'événement textBox1_DragOver. Passez la position de la souris contenue dans les arguments de l'événement DragOver à 'textBox1.GetCharIndexFromPosition()'

Vous devriez pouvoir utiliser la position char pour définir la position du curseur.

Voici la documentation GetCharIndexFromPosition

2

Ceci est en fait vraiment irritant comme GetCharIndexFromPosition (évidemment) manque une position de caret, car il y a une position de caret supplémentaire que il y a des personnages (un de plus à la fin). Je l'utilise pour définir SelectionStart sur DragOver et Insert sur DragDrop.

private int GetCaretIndexFromPoint(TextBox tb, int x, int y) 
    { 
     Point p = tb.PointToClient(new Point(x, y)); 
     int i = tb.GetCharIndexFromPosition(p); 
     if (i == tb.Text.Length - 1) 
     { 
      Point c = tb.GetPositionFromCharIndex(i); 
      if (p.X > c.X) 
       i++; 
     } 
     return i; 
    } 

Pas tout à fait parfait, mais cela fait l'affaire. Si quelqu'un trouve une version native s'il vous plaît faites le moi savoir :)

+0

Très irritant en effet. Je dois peut-être essayer ça. Ma solution de contournement consistait simplement à ajouter un espace supplémentaire au démarrage, afin que vous puissiez déposer à la fin du texte, puis supprimer l'espace sur déposer. –

8

Ce qui m'a manqué dans tous ces conseils sur le glisser-déposer est de rendre le texte de texte visible. Finalement, j'ai trouvé que vous devez simplement mettre l'accent dans le contrôle! Le code final du gestionnaire d'événements textBox1.DragOver sera donc le suivant. J'ai inclus la fonction GetCaretIndexFromPoint de la réponse précédente:

/// <summary> 
/// Gives visual feedback where the dragged text will be dropped. 
/// </summary> 
private void textBox1_DragOver(Object sender, System.Windows.Forms.DragEventArgs e) 
{ 
    // fake moving the text caret 
    textBox1.SelectionStart = GetCaretIndexFromPoint(textBox1, e.X, e.Y); 
    textBox1.SelectionLength = 0; 
    // don't forget to set focus to the text box to make the caret visible! 
    textBox1.Focus(); 
} 

/// <remarks> 
/// GetCharIndexFromPosition is missing one caret position, as there is one extra caret 
/// position than there are characters (an extra one at the end). 
/// </remarks> 
private int GetCaretIndexFromPoint(System.Windows.Forms.TextBox box, int x, int y) 
{ 
    Point realPoint = box.PointToClient(newPoint(x, y)); 
    int index = box.GetCharIndexFromPosition(realPoint); 
    if (index == box.Text.Length - 1) 
    { 
     Point caretPoint = box.GetPositionFromCharIndex(index); 
     if (realPoint.X > caretPoint.X) 
     { 
      index += 1; 
     } 
    } 
    return index; 
} 
1

Je cherchais une application WPF de cette solution et ne pouvait pas trouver un. Donc mis en œuvre comme suit (Crédits à l'auteur de la solution d'origine). J'espère que cela aidera quelqu'un qui cherche une version WPF.

/// <summary> 
    /// Handles the Preview DragOver event to set the textbox selection at the precise place where the user dropped the dragged text 
    /// </summary> 
    private static void element_PreviewDragOver(object sender, DragEventArgs dragEventArgs) 
    { 
     TextBox textBox = sender as TextBox; 
     if (textBox != null && dragEventArgs != null) 
     { 
      // Set the caret at the position where user ended the drag-drop operation 
      Point dropPosition = dragEventArgs.GetPosition(textBox); 

      textBox.SelectionStart = GetCaretIndexFromPoint(textBox, dropPosition); 
      textBox.SelectionLength = 0; 

      // don't forget to set focus to the text box to make the caret visible! 
      textBox.Focus(); 
      dragEventArgs.Handled = true; 
     } 
    } 

    /// <summary> 
    /// Gets the caret index of a given point in the given textbox 
    /// </summary> 
    /// <param name="textBox"></param> 
    /// <param name="point"></param> 
    /// <returns></returns> 
    private static int GetCaretIndexFromPoint(TextBox textBox, Point point) 
    { 
     int index = textBox.GetCharacterIndexFromPoint(point, true); 

     // GetCharacterIndexFromPoint is missing one caret position, as there is one extra caret position than there are characters (an extra one at the end). 
     // We have to add that caret index if the given point is at the end of the textbox 
     if (index == textBox.Text.Length - 1) 
     { 
      // Get the position of the character index using the bounding rectangle 
      Rect caretRect = textBox.GetRectFromCharacterIndex(index); 
      Point caretPoint = new Point(caretRect.X, caretRect.Y); 

      if (point.X > caretPoint.X) 
      { 
       index += 1; 
      } 
     } 
     return index; 
    } 

    /// <summary> 
    /// Handler for preview drag event in a textbox 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="dragEventArgs"></param> 
    private static void element_PreviewDrop(object sender, DragEventArgs dragEventArgs) 
    { 
     TextBox textBox = sender as TextBox; 
     if (textBox != null && dragEventArgs != null && dragEventArgs.Data != null && dragEventArgs.Data.GetDataPresent(DataFormats.StringFormat)) 
     { 
      string newText = dragEventArgs.Data.GetData(DataFormats.StringFormat) as string; 
      if (!string.IsNullOrEmpty(newText)) 
      { 
       // do your custom logic here 
       textBox.Focus(); 
      } 
      dragEventArgs.Handled = true; 
     } 
    } 
1

pour émuler le comportement d'outils communs (tel que le bloc-notes), la fonction GetCaretIndexFromPoint() doit vérifier à la fois les coordonnées X et Y.

/// <summary> 
/// Gives visual feedback where the dragged text will be dropped. 
/// </summary> 
private void textBox1_DragOver(Object sender, System.Windows.Forms.DragEventArgs e) 
{ 
    // fake moving the text caret 
    textBox1.SelectionStart = GetCaretIndexFromPoint(textBox1, e.X, e.Y); 
    textBox1.SelectionLength = 0; 
    // don't forget to set focus to the text box to make the caret visible! 
    textBox1.Focus(); 
} 

/// <remarks> 
/// GetCharIndexFromPosition is missing one caret position, as there is one extra caret 
/// position than there are characters (an extra one at the end). 
/// </remarks> 
private int GetCaretIndexFromPoint(System.Windows.Forms.TextBox box, int x, int y) 
{ 
    Point realPoint = box.PointToClient(new Point(x, y)); 
    int index = box.GetCharIndexFromPosition(realPoint); 
    if (index == box.Text.Length - 1) 
    { 
     Point caretPoint = box.GetPositionFromCharIndex(index); 
     if ((realPoint.X > caretPoint.X) || (realPoint.Y > caretPoint.y)) 
     { 
      index += 1; 
     } 
    } 
    return index; 
} 

Vous pouvez voir la différence si le dernier caractère dans la zone de texte est une nouvelle ligne après une ligne de texte et vous déposer le texte ci-dessous et à gauche du caretPoint par rapport ci-dessous et à droite de la caretPoint .

Merci à user468106 pour son excellente réponse!

Questions connexes