Drag And Drop и Scroll в TreeView C#
Не так давно пришлось делать DragAndDrop для TreeView и с удивлением обнаружил что на .NET не работает сама собой прокрутка (никак не работает, как выяснилось Microsoft признаёт что есть такая проблема, и предлагают её решать способом описанным ниже).
Итак сам способ.
Вопервых импортируем функцию из user32 — SendMessage
Для этого разумеется не забываем включить в проект (using System.Runtime.InteropServices;)
[DllImport("user32.dll")]
public static extern int SendMessage(
int hWnd, // handle to destination window
uint Msg, // message
long wParam, // first message parameter
long lParam // second message parameter
);
Задаём две переменные — они будут обозначать куда мы движемся, в нашей реализации…
public bool tree_go_down = false;
public bool tree_go_up = false;
Создаём таймер (в нашем случае просто кидаем его на форму) и создаём событие по нему:
private void timer1_Tick(object sender, EventArgs e)
{
if (tree_go_down == true) //Здесь отправляем сообщение на Scroll вниз
{
SendMessage(treeView1.Handle.ToInt32(), 277, 1, 0);
}
if (tree_go_up == true) //Здесь отправляем сообщение на Scroll вверх
{
SendMessage(treeView1.Handle.ToInt32(), 277, 0, 0);
}
}
На событие DragOver нашего TreeView делаем вот такое вот безобразие, суть которого сводится к изменению скорости
прокрутки при более близком подходе к границам нашего TreeView.
private void treeView1_DragOver(object sender, DragEventArgs e)
{
//Определяем где форма и начальные координаты.
int top_y = this.Top+30;//30 - высота заголовка формы.
int top_x = this.Left;
//Выводим координатки вверх формы.
this.Text = e.X.ToString() + ":" + e.Y.ToString() + " - "+top_x.ToString()+":"+top_y.ToString();
//Скролл вверх.
if (e.Y < 150 + top_y)
{
timer1.Interval = 100;
tree_go_up = true;
tree_go_down = false;
}
if (e.Y < 100 + top_y)
{
timer1.Interval = 50;
tree_go_up = true;
tree_go_down = false;
}
if (e.Y < 50 + top_y)
{
timer1.Interval = 25;
tree_go_up = true;
tree_go_down = false;
}
//Скролл вниз.
if (e.Y > treeView1.Height - 150)
{
timer1.Interval = 100;
tree_go_up = false;
tree_go_down = true;
}
if (e.Y > treeView1.Height - 100)
{
timer1.Interval = 50;
tree_go_up = false;
tree_go_down = true;
}
if (e.Y > treeView1.Height - 50)
{
timer1.Interval = 25;
tree_go_up = false;
tree_go_down = true;
}
//Стоп машина!
if (e.Y < treeView1.Height - 150)
{
tree_go_down = false;
}
if (e.Y > 150 + top_y)
{
tree_go_up = false;
}
e.Effect = DragDropEffects.Copy;
}
Начинаем Drag And Drop (начало перетаскивания элемента).
TreeNode StartNode = new TreeNode();
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
{
timer1.Enabled = true;
TreeNode aNode = (TreeNode)e.Item;
StartNode = new TreeNode();
StartNode.Text = aNode.Text;
StartNode.Tag = aNode.Tag;
StartNode = aNode; DoDragDrop(aNode, DragDropEffects.Copy);
}
Это делаем при бросании элемента (конец перетаскивания элемента).
private void treeView1_DragDrop(object sender, DragEventArgs e)
{
timer1.Enabled = false;
TreeNode TargetNode = treeView1.GetNodeAt(e.X, e.Y-top_y);
//Манипуляции с самим деревом.
treeView1.SelectedNode = TargetNode;
TreeNode node = new TreeNode();
node.Tag = StartNode.Tag;
node.Text = StartNode.Text;
treeView1.SelectedNode.Nodes.Add(node);
StartNode.Remove();
}
Собственно всё, должно работать.
Скачать пример с исходником можно тут:
Скачать файл: treeviewscroll.rar [40 Kb] (cкачиваний: 6)