2009-05-27 3 views
1

У меня есть TreeView и многострочное текстовое поле вместе в той же форме в форме Windows. У меня есть настройка перетаскивания, чтобы я мог перетащить узел из TreeView в текстовое поле и вставить текст в текстовое поле (это работает).Как перемещать вставку в текстовое поле при принятии Drop

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

Вот мой текущий код:

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

Вот что я искал. Благодаря! –

ответ

3

Я думаю, что вы хотите посмотреть на обработку события textBox1_DragOver. Передайте позицию мыши, содержащуюся в событии DragOver, args к «textBox1.GetCharIndexFromPosition()»

Вы должны иметь возможность использовать положение символа для установки положения каретки.

Вот документация GetCharIndexFromPosition

2

Это на самом деле очень раздражает, как GetCharIndexFromPosition (очевидно) не хватает на одну позиции каре, так как есть одна дополнительная позиция каретки, чем есть символы (дополнительная один в конце). Я использую это, чтобы установить SelectionStart на DragOver и Insert на 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; 
    } 

Не совсем совершенный, но он выполняет свою работу. Если кто-то найдет родную версию, пожалуйста, дайте мне знать :)

+0

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

8

То, что я пропустил во всех этих рекомендациях о перетаскивании, делает текст заметным. В конце концов, я обнаружил, что вам просто нужно установить фокус в управление! Таким образом, окончательный код для обработчика событий textBox1.DragOver будет следующим. Я включил функцию GetCaretIndexFromPoint из предыдущего ответа:

/// <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

Я искал реализацию WPF этого решения и не мог найти. Так реализовано следующим образом (Кредиты оригинальному автору решения). Надеюсь, это поможет кому-то, кто ищет версию 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

Для того, чтобы эмулировать поведение обычных инструментов (например, Блокнот), функция GetCaretIndexFromPoint() должны проверить оба Х и 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; 
} 

Вы можете увидеть разницу, если последний символ в текстовом поле новой строки после строки текста и вы падаете текст ниже и слева от caretPoint против ниже и справа от caretPoint ,

Благодарим за внимание пользователя468106 за его отличный ответ!