Windows 表单中 Treeview 中的 Aftercheck 和 AfterSelect 事件
Aftercheck and AfterSelect events in Treeview in Windows Forms
我正在设置一个新窗体,我在检查和取消检查子节点时遇到了一些问题。在这个 short clip
中更容易看出问题
通常它工作正常但有时会卡住(我认为与选择有冲突但我不确定)并且方法应用不正确。
我有这个方法来检查和取消检查孩子:
private void Treeview_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action != TreeViewAction.Unknown)
if (e.Node.Checked)
{
CheckAll(e.Node.Nodes);
}
if (e.Node.Checked == false)
{
Uncheckall(e.Node.Nodes);
}
}
public void Uncheckall(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = false;
foreach (TreeNode node1 in node.Nodes)
{
node1.Checked = false;
foreach (TreeNode node2 in node1.Nodes)
{
node2.Checked = false;
}
}
}
}
public void CheckAll(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = true;
foreach (TreeNode node1 in node.Nodes)
{
node1.Checked = true;
foreach (TreeNode node2 in node1.Nodes)
{
node2.Checked = true;
}
}
}
}
而且我已尝试将选择设为空:
private void TreeView_Select(object sender, TreeViewEventArgs e)
{
TreeView.SelectedNode = null;
}
但问题依旧。有任何想法吗?谢谢
我在评论中提到的 question 的答案向我们展示了如何遍历 TreeView
节点的不同方式。为此,您需要一个递归函数,它是一个调用自身的函数。
现在,回到您的代码。您不需要创建两个函数来检查和取消检查节点,也不需要为每个节点、子节点和子节点的子节点使用 foreach
等。请尝试以下操作:
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action == TreeViewAction.Unknown) { return; }
foreach (TreeNode tn in GetNodes(e.Node))
tn.Checked = e.Node.Checked;
}
private static IEnumerable<TreeNode> GetNodes(TreeNode parentNode)
{
foreach (TreeNode tn in parentNode.Nodes)
{
yield return tn;
foreach (TreeNode child in GetNodes(tn))
{
yield return child;
}
}
}
这样,您可以使用此迭代器对您的节点执行其他操作,而不仅仅是 check/uncheck 它们。
编辑
You can see this strange behaviour in the seconds 7, 10, 15.
我明白你的意思了。
当您在节点上鼠标单击速度过快时会出现该行为,因此您实际上是在执行鼠标单击、鼠标双击序列。默认情况下,树视图控件不会通过鼠标双击切换节点的检查状态,除非您告诉它这样做。如何? PhilP in this 问题已回答。
- 创建一个新的class继承树视图控件并覆盖WndProc事件如下:
class TreeViewEx : TreeView
{
public TreeViewEx()
{ }
#region This extra to reduce the flickering
private const int TVM_SETEXTENDEDSTYLE = 0x1100 + 44;
private const int TVM_GETEXTENDEDSTYLE = 0x1100 + 45;
private const int TVS_EX_DOUBLEBUFFER = 0x4;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
protected override void OnHandleCreated(EventArgs e)
{
SendMessage(Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)TVS_EX_DOUBLEBUFFER);
base.OnHandleCreated(e);
}
#endregion
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x203 && CheckBoxes)
{
int x = m.LParam.ToInt32() & 0xffff;
int y = (m.LParam.ToInt32() >> 16) & 0xffff;
TreeViewHitTestInfo hitTestInfo = HitTest(x, y);
if (hitTestInfo.Node != null && hitTestInfo.Location == TreeViewHitTestLocations.StateImage)
{
OnBeforeCheck(new TreeViewCancelEventArgs(hitTestInfo.Node, false, TreeViewAction.ByMouse));
hitTestInfo.Node.Checked = !hitTestInfo.Node.Checked;
OnAfterCheck(new TreeViewEventArgs(hitTestInfo.Node, TreeViewAction.ByMouse));
m.Result = IntPtr.Zero;
return;
}
}
base.WndProc(ref m);
}
}
在包含您的 TreeView
的表单设计器中,将 TreeView
的类型更改为我们刚刚创建的扩展类型。
使用相同的代码切换检查状态。
重建您的项目。
就这些了。
这是一个快速演示。我疯狂地点击鼠标和双击。但是,它可以正常工作。希望。
Related
◉
我正在设置一个新窗体,我在检查和取消检查子节点时遇到了一些问题。在这个 short clip
中更容易看出问题通常它工作正常但有时会卡住(我认为与选择有冲突但我不确定)并且方法应用不正确。
我有这个方法来检查和取消检查孩子:
private void Treeview_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action != TreeViewAction.Unknown)
if (e.Node.Checked)
{
CheckAll(e.Node.Nodes);
}
if (e.Node.Checked == false)
{
Uncheckall(e.Node.Nodes);
}
}
public void Uncheckall(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = false;
foreach (TreeNode node1 in node.Nodes)
{
node1.Checked = false;
foreach (TreeNode node2 in node1.Nodes)
{
node2.Checked = false;
}
}
}
}
public void CheckAll(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = true;
foreach (TreeNode node1 in node.Nodes)
{
node1.Checked = true;
foreach (TreeNode node2 in node1.Nodes)
{
node2.Checked = true;
}
}
}
}
而且我已尝试将选择设为空:
private void TreeView_Select(object sender, TreeViewEventArgs e)
{
TreeView.SelectedNode = null;
}
但问题依旧。有任何想法吗?谢谢
我在评论中提到的 question 的答案向我们展示了如何遍历 TreeView
节点的不同方式。为此,您需要一个递归函数,它是一个调用自身的函数。
现在,回到您的代码。您不需要创建两个函数来检查和取消检查节点,也不需要为每个节点、子节点和子节点的子节点使用 foreach
等。请尝试以下操作:
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action == TreeViewAction.Unknown) { return; }
foreach (TreeNode tn in GetNodes(e.Node))
tn.Checked = e.Node.Checked;
}
private static IEnumerable<TreeNode> GetNodes(TreeNode parentNode)
{
foreach (TreeNode tn in parentNode.Nodes)
{
yield return tn;
foreach (TreeNode child in GetNodes(tn))
{
yield return child;
}
}
}
这样,您可以使用此迭代器对您的节点执行其他操作,而不仅仅是 check/uncheck 它们。
编辑
You can see this strange behaviour in the seconds 7, 10, 15.
我明白你的意思了。
当您在节点上鼠标单击速度过快时会出现该行为,因此您实际上是在执行鼠标单击、鼠标双击序列。默认情况下,树视图控件不会通过鼠标双击切换节点的检查状态,除非您告诉它这样做。如何? PhilP in this 问题已回答。
- 创建一个新的class继承树视图控件并覆盖WndProc事件如下:
class TreeViewEx : TreeView
{
public TreeViewEx()
{ }
#region This extra to reduce the flickering
private const int TVM_SETEXTENDEDSTYLE = 0x1100 + 44;
private const int TVM_GETEXTENDEDSTYLE = 0x1100 + 45;
private const int TVS_EX_DOUBLEBUFFER = 0x4;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
protected override void OnHandleCreated(EventArgs e)
{
SendMessage(Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)TVS_EX_DOUBLEBUFFER);
base.OnHandleCreated(e);
}
#endregion
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x203 && CheckBoxes)
{
int x = m.LParam.ToInt32() & 0xffff;
int y = (m.LParam.ToInt32() >> 16) & 0xffff;
TreeViewHitTestInfo hitTestInfo = HitTest(x, y);
if (hitTestInfo.Node != null && hitTestInfo.Location == TreeViewHitTestLocations.StateImage)
{
OnBeforeCheck(new TreeViewCancelEventArgs(hitTestInfo.Node, false, TreeViewAction.ByMouse));
hitTestInfo.Node.Checked = !hitTestInfo.Node.Checked;
OnAfterCheck(new TreeViewEventArgs(hitTestInfo.Node, TreeViewAction.ByMouse));
m.Result = IntPtr.Zero;
return;
}
}
base.WndProc(ref m);
}
}
在包含您的
TreeView
的表单设计器中,将TreeView
的类型更改为我们刚刚创建的扩展类型。使用相同的代码切换检查状态。
重建您的项目。
就这些了。
这是一个快速演示。我疯狂地点击鼠标和双击。但是,它可以正常工作。希望。
Related
◉