代码之家  ›  专栏  ›  技术社区  ›  Ted Elliott

接受拖放时如何在文本框上移动插入插入符号

  •  2
  • Ted Elliott  · 技术社区  · 17 年前

    我有一个TreeView和一个多行文本框,在Windows窗体的同一个窗体上。我有拖放设置,这样我可以将一个节点从树状视图拖到文本框中,并将文本插入文本框中(这是可行的)。

    以下是我当前的代码:

        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);
            }
        }
    
    5 回复  |  直到 17 年前
        1
  •  8
  •   user468106    15 年前

    我在所有关于拖放的建议中遗漏的是使文本插入符号可见。最终,我发现您只需将焦点设置到控件中!因此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;
    }
    
        2
  •  3
  •   Kevin Pullin    17 年前

    我想你应该看看如何处理textBox1_DragOver事件。将DragOver事件参数中包含的鼠标位置传递给“textBox1.GetCharIndexFromPosition()”

    这是您的文档 GetCharIndexFromPosition

        3
  •  3
  •   Jamie Kitson    16 年前

    这实际上是非常令人恼火的,因为GetCharIndexFromPosition(显然)缺少一个插入符号位置,因为有一个额外的插入符号位置比有个字符多(末尾有一个额外的)。我用它在DragOver上设置SelectionStart,在DragDrop上设置Insert。

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

        4
  •  2
  •   Ann Catherine Jose    13 年前

        /// <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;
            }
        }
    
        5
  •  1
  •   Mike F    12 年前

    要模拟常用工具(如记事本)的行为,GetCaretIndexFromPoint()函数必须同时检查X和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;
    }
    

    感谢用户468106给出的精彩回答!

    推荐文章