Windows Forms TreeView 总是在焦点上选择一个节点

5
在Windows Forms中,TreeView控件在重新获得焦点时似乎总是需要选择一个节点。如果我没有选中任何节点,当该TreeView控件重新获得焦点时,我会收到一个AfterSelect事件,并且第一个节点会被选中,即使我没有使用键盘、鼠标或编程方式来选择它。我找到的唯一解决方法是检查TreeViewCancelEventArgs.Action是否等于TreeViewAction.Unknown,然后取消选择。这种方法看起来非常笨拙,所以我想知道是否有其他方法可以解决这个问题。
5个回答

6

我认为在这种情况下使用TreeViewAction.Unknown并不是最理想的选择。考虑使用BeforeSelect事件,该事件提供了一个机会来阻止AfterSelect事件的发生。

创建一个GotFocus事件处理程序来设置一个标志。然后,创建一个BeforeSelect事件处理程序,如果标志被设置,就取消事件并清除标志。例如:

private bool treeViewWasNewlyFocused = false;

private void TreeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
    if(treeViewWasNewlyFocused)
    {
        e.Cancel = true;
        treeViewWasNewlyFocused = false;
    }
}

private void TreeView1_GotFocus(object sender, EventArgs e)
{
    treeViewWasNewlyFocused = true;
}

如果在TreeView获取焦点时已选择了一个节点,那么这段代码会发生什么呢?那么BeforeSelect事件将不会被触发,treeViewHasNewlyFocused将保持为true。我猜测这会导致用户下一次有意选择节点的操作被取消。 - Fredrik Mörk
我确实使用BeforeSelect事件来取消选择。我使用一个标志,但是我使用一个标志来指定是否正在以编程方式进行树形视图选择,因为程序化选择的操作报告为“未知”。这似乎有效,但是这种行为似乎是TreeView控件中的一个错误,因为这种行为没有意义,我没有在任何地方看到它被记录。 - Michael Kelley

6
我通过关闭树形视图的TabStop来解决了这个问题。

3

我曾经遇到过同样的问题(但在紧凑框架上),其中 BeforeSelect 事件没有暴露出来(我很失望)。

但是,我找到了一个相当简洁的解决方案,并希望能够帮助其他人!!

我创建了一个派生的 TreeView 控件(以便可以一次选择多个项目),但也会在获取焦点时更正“自动”选择第一个节点。

  • public class TreeView_MultSel : System.Windows.Forms.TreeView

然后,我覆盖了事件处理程序,如下所示:

/// <summary>
/// //This actually occurs AFTER actual Treeview control:
///   -  Got Focus in reality
///   -  Executed the "innate" behaviour (like a button showing "depressed")
///   -  The "innate and UNWANTED behaviour of the Treeview is to selected the first Node 
///          when gets the focus.
///The key here is the Treeview executes in this order (when Tree Selected and didn't have focus):
///   -  First the Node is selected (before OnGotFocus is executed)
///         Since when LostFocus "treeHasFocus" = false the OnAfterSelect handler isn't called!!
///
///   -  Then the OnGotFocus is called:
///         This will set treeHasFocus to True and will not react to selections
/// </summary>
/// <param name="e"></param>
protected override void OnGotFocus(EventArgs e)
{
    treeHasFocus = true;
    //base.OnGotFocus(e);
}

/// <summary>
/// Alot easier to handle here (in Derived TreeView control then using all kinds of 
///     -= events to try to prevent.
/// 
/// This was the cleanest way I could find (prevent firing of AfterSelect)
/// </summary>
/// <param name="e"></param>
protected override void OnLostFocus(EventArgs e)                
{                                                               
    treeHasFocus = false;                                       
    //base.OnLostFocus(e);
}

/// <summary>
/// -  Treeview Control defaults to selecting the first node (when gets focus)
/// -  We do NOT want this - since would automatically Highlight the first node (select)
/// -  treeHasFocus is NOT true for the first unwanted "automatic" selection of the first item
/// -  Upon loosing Focus, the AfterSelect handler is never called.
/// </summary>
/// <param name="e"></param>
protected override void OnAfterSelect(TreeViewEventArgs e)      
{                                                               
    if (treeHasFocus)                                           
        base.OnAfterSelect(e);                                   
    this.SelectedNode = null;                                   
}

0
修复了我自己的版本中的相同问题,以下是代码。
private TreeNode _selectedNode;

public FormMain()
{
    InitializeComponent();
    myTreeView.LostFocus += (sender, args) => _selectedNode = myTreeView.SelectedNode;
    myTreeView.GotFocus += (sender, args) => myTreeView.SelectedNode = _selectedNode;
}

0
通过发送 lparam 为 0 的 TVM_SELECTITEM 解决了该问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接