|
我在开发中遇到这么一个问题:如果结点数过多时(近万个),使用TreeView控件加载时速度非常慢。我就想能否做到一开始只加载部分结点,当用户翻页时再加载需要的新结点。但我翻了一个TreeView的资料,没有发现有针对滚动条的事件。于是就自己重载了TreeView控件,添加了对滚动条事件的支持。
添加滚动条事件支持
主要的实现代码很简单,如下所示:
public class MyTreeView : System.Windows.Forms.TreeView
 ...{
private const int WM_VSCROLL = 0x0115; //滚动条事件
private const int WM_MOUSEWHEEL = 0x020A; //鼠标滚轮事件
private const int SB_ENDSCROLL = 8; //滚动结束标志

public event EventHandler VerticalScrolled;

protected override void WndProc(ref Message m)
 ...{
if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL)
 ...{
if (m.WParam.ToInt32() == SB_ENDSCROLL)
 ...{
VerticalScrolled(this, new EventArgs());
}
}
base.WndProc(ref m);
}

}
事件添加好了,现在要做的事情就是动态添加节点了,又出现了一个问题就是,我如何获取当前屏幕区域内的最后一个节点,我使用了如下一个方法获取当前区域内的最后一个树结点:
private TreeNode GetLastNodeInScreen(TreeView tv)
 ...{
TreeNode node = null;
for (int x = tv.ClientSize.Width; x > 0; x -= 5)
 ...{
int y;
for (y = tv.ClientSize.Height; y > 0; y -= 5)
 ...{
node = tv.GetNodeAt(x, y);
if (node != null)
 ...{
break;
}
}
if (y > 0)
break;
}
return node;
}
动态加载的关键代码如下所示:
private MyTreeView Tree;

 /**//// <summary>
/// 要载入的全部内容
/// </summary> private List<string> Nodes;

 /**//// <summary>
/// 每次载入的行数
/// </summary> private const int PageRows = 30;

 /**//// <summary>
/// 总页数
/// </summary> private int PageCount;

 /**//// <summary>
/// 加载的页数
/// </summary> private int LoadedPage = 0;

 /**//// <summary>
/// 滚动树内容时触发的事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param> private void TreeScrolled(object sender, EventArgs e)
 ...{
if (this.LoadedPage == this.PageCount)
return;

TreeNode last_node_sc = this.GetLastNodeInScreen(this.Tree);

if (this.Tree.Nodes.Count - last_node_sc.Index < 10)
 ...{
this.LoadPage(this.LoadedPage + 1);
}
}


private void Form1_Load(object sender, EventArgs e)
 ...{
this.Tree = new MyTreeView();
this.Tree.Parent = this;
this.Controls.Add(this.Tree);
this.Tree.Top = 10;
this.Tree.Left = 10;
this.Tree.Width = 150;
this.Tree.Height = 200;
this.Tree.VerticalScrolled += new EventHandler(this.TreeScrolled);

this.Nodes = new List<string>();
for (int i = 0; i < 1000; i++)
 ...{
this.Nodes.Add("Node" + i.ToString().PadLeft(4));
}
this.PageCount = (int)Math.Ceiling(Convert.ToDouble(this.Nodes.Count) / PageRows);
this.LoadPage(1);
}

 /**//// <summary>
/// 载入页
/// </summary>
/// <param name="page_no"></param> private void LoadPage(int page_no)
 ...{
for (int i = this.LoadedPage * PageRows; i < page_no * PageRows - 1 && i < this.Nodes.Count; i++)
 ...{
TreeNode node = new TreeNode();
node.Text = this.Nodes[i];
this.Tree.Nodes.Add(node);
}
this.LoadedPage = page_no;
}
|