I am pasting an item from a TreeView
to a TextBox
, but I want to paste that item in the mouse's current position and also show a caret like the image below.
Image with caret:
Here is my code:
private void tvOperador_ItemDrag(object sender, ItemDragEventArgs e)
{
var node = (TreeNode)e.Item;
if (node.Level > 0)
{
DoDragDrop(node.Text, DragDropEffects.Copy);
}
}
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string))) e.Effect = DragDropEffects.Copy;
}
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.Text += split[1];
}
}
This is tricky as the Drag&Drop
operation keeps the mouse captured, so you can't use the mouse events..
One way is to set up a Timer
to do the work..:
Timer cursTimer = new Timer();
void cursTimer_Tick(object sender, EventArgs e)
{
int cp = txtExpresion.GetCharIndexFromPosition(
txtExpresion.PointToClient(Control.MousePosition));
txtExpresion.SelectionStart = cp;
txtExpresion.SelectionLength = 0;
txtExpresion.Refresh();
}
The Timer
uses the Control.MousePosition
function to determined the cursor position every 25ms or so, sets the caret and updates the TextBox
.
In your events you initialize it and make sure the TextBox
has focus; finally you add the string at the current selection:
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)))
{
e.Effect = DragDropEffects.Copy;
txtExpresion.Focus();
cursTimer = new Timer();
cursTimer.Interval = 25;
cursTimer.Tick += cursTimer_Tick;
cursTimer.Start();
}
}
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
cursTimer.Stop();
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.SelectedText = split[1]
}
}
A different way to solve it would be to not use normal Drag&Drop and only code the mouse events but this one worked ok a my first tests.
Update
While the above solution does work, using a Timer
seems not exactly elegant. Much better to use the DragOver
event, as seen in Reza's answer. But instead of painting a cursor, why not do the real thing, i.e. take control of the actual I-beam..?
The DragOver
event is called all the time during the move so it works pretty much like MousMove
would: So here is a merger of the two solutions, which I believe is the best way to do it:
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.SelectionLength = 0;
txtExpresion.SelectedText = split[1];
}
}
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)))
{
e.Effect = DragDropEffects.Copy;
txtExpresion.Focus();
}
}
private void txtExpresion_DragOver(object sender, DragEventArgs e)
{
int cp = txtExpresion.GetCharIndexFromPosition(
txtExpresion.PointToClient(Control.MousePosition));
txtExpresion.SelectionStart = cp;
txtExpresion.Refresh();
}
You can draw a caret over TextBox
in DragOver
event. Also set the SelectionStart
to the char index you get from mouse position. Then in DragDrop
event, just set SelectedText
.
private void textBox1_DragOver(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
var position = textBox1.PointToClient(Cursor.Position);
var index = textBox1.GetCharIndexFromPosition(position);
textBox1.SelectionStart = index;
textBox1.SelectionLength = 0;
textBox1.Refresh();
using (var g = textBox1.CreateGraphics())
{
var p = textBox1.GetPositionFromCharIndex(index);
g.DrawLine(Pens.Black, p.X, 0, p.X, textBox1.Height);
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string txt = (System.String)e.Data.GetData(typeof(System.String));
textBox1.SelectedText = txt;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With