问题描述
TreeView过长;
不点击节点,鼠标滚轮可以让滚动条滚动;
点击节点,按住不放,拖拽节点到页面外部,页面不会自动滚动,鼠标滚轮也不会让滚动条滚动。
解决思路
在查过官方文档就知道C#的treeview封装了滚动条事件,没有提供相应的api接口,想要重载滚动条的事件是行不通的。
由于只有按住节点的时候才有这个滚动的需求,因此我想了一种“曲线救国”的方法:重载TreeView的拖拽事件。
QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
这个是TreeView的拖拽事件,处于节点拖拽状态下才会触发该事件函数。
如果C#写多了,就会知道TreeView有个节点跳转的功能,类似页面右下角的“返回顶部”的功能,只要把焦点定位和拖拽就可以让页面自动滚动。
(我没实现重载拖拽时的鼠标滚轮,因为节点焦点乱飘不适合我的需求)
代码
事前工作1:向上、向下滚动定时器
/// <summary>
/// 拖拽上滚动定时器
/// </summary>
private Timer ScrollUpDelayTimer = new Timer();
/// <summary>
/// 编辑器拖拽下滚动定时器
/// </summary>
private Timer ScrollDownDelayTimer = new Timer();
public MYTreeView()
{
InitializeComponent();
// 初始化拖拽滚动定时器
// 初始化时间
ScrollUpDelayTimer.Interval = ScrollDelayTimerMS;
ScrollDownDelayTimer.Interval = ScrollDelayTimerMS;
// 初始化事件
ScrollUpDelayTimer.Tick += new EventHandler(ScrollUpEvent);
ScrollDownDelayTimer.Tick += new EventHandler(ScrollDownEvent);
}
事前工作2:向上、向下滚动事件
/// <summary>
/// 向上滚
/// </summary>
/// <param name="currentIndex"></param>
private void ScrollUp()
{
int currentIndex = treeView.SelectedNode.Index;
if (currentIndex >= 1)
{
currentIndex--;
treeView.SelectedNode = treeView.Nodes[currentIndex];
treeView.Nodes[currentIndex].EnsureVisible();
}
}
private void ScrollUpEvent(object sender, EventArgs e)
{
ScrollUp();
}
/// <summary>
/// 向下滚
/// </summary>
/// <param name="currentIndex"></param>
private void ScrollDown()
{ int currentIndex = treeView.SelectedNode.Index;
if (currentIndex < treeView.Nodes.Count - 1)
{
currentIndex++;
treeView.SelectedNode = treeView.Nodes[currentIndex];
treeView.Nodes[currentIndex].EnsureVisible();
int childIndex = this.treeView.Nodes[currentIndex].Nodes.Count - 1;
if (childIndex >= 0)
{
treeView.Nodes[currentIndex].Nodes[childIndex].EnsureVisible();
}
}
}
private void ScrollDownEvent(object sender, EventArgs e)
{
ScrollDown();
}
准备完成,重载TreeView的拖拽事件
/// <summary>
/// 拖拽改变滚动条位置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MYTreeView_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
TreeNode node = treeView.SelectedNode;
Point currentPoint = treeView.PointToClient(new Point(Control.MousePosition.X, Control.MousePosition.Y));
while (node.Parent != null)
{
node = node.Parent;
}
int currentIndex = node.Index;
if (currentPoint.Y < 0 && currentIndex >= 1)
{
ScrollUpDelayTimer.Start();
}
else if (currentPoint.Y > treeView.Height && currentIndex < treeView.Nodes.Count - 1)
{
ScrollDownDelayTimer.Start();
}
else
{
ScrollUpDelayTimer.Stop();
ScrollDownDelayTimer.Stop();
}
}
为了方便测试,还可以加个快捷键在里面
/// <summary>
/// 拖拽改变滚动条位置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FlowEditorTreeView_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
TreeNode node = treeView.SelectedNode;
Point currentPoint = treeView.PointToClient(new Point(Control.MousePosition.X, Control.MousePosition.Y));
while (node.Parent != null)
{
node = node.Parent;
}
int currentIndex = node.Index;
// CTRL向上滚, ALT向下滚
if (e.KeyState == 9 || e.KeyState == 33)
{
if (e.KeyState == 9 && currentIndex >= 1)
{
ScrollUp();
}
else if (e.KeyState == 33 && currentIndex < treeView.Nodes.Count - 1)
{
ScrollDown();
}
}
else
{
if (currentPoint.Y < 0 && currentIndex >= 1)
{
ScrollUpDelayTimer.Start();
}
else if (currentPoint.Y > treeView.Height && currentIndex < treeView.Nodes.Count - 1)
{
ScrollDownDelayTimer.Start();
}
else
{
ScrollUpDelayTimer.Stop();
ScrollDownDelayTimer.Stop();
}
}
}