views:

1788

answers:

2

The TreeView in Windows Forms always seems to want a node selected when it regains focus. If I have no nodes selected, and that treeview gains focus, I'll get an AfterSelect event with the first node selected, even though I didn't select it using the keyboard, mouse, or programmatically. The only workaround I can find is to check if the TreeViewCancelEventArgs.Action equals TreeViewAction.Unknown and then canceling the selection. This seems really hacky, so I'm wondering if there's another way to fix this.

+2  A: 

I agree that using TreeViewAction.Unknown in this case is less than desirable. Consider using the BeforeSelect event, which provides an opportunity to prevent the AfterSelect event.

Create a GotFocus event handler that sets a flag. Then, create a BeforeSelect event handler that, if the flag is set, cancels the event and clears the flag. For example:

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;
}
What happens with this code if there is a node selected when the treeview gets focus. Then BeforeSelect will not be raised, the treeViewHasNewlyFocused will remain true. My guess is that this would lead to the next deliberate node selection from the user being canceled.
Fredrik Mörk
I do use the BeforeSelect event to cancel. I do use a flag, but I use a flag to specify if the treeview selection is being made programmatically as the action reported for a programmatic selection is reported as "Unknown". That seems to work, but it seems that this behavior is a bug in the TreeView control as the behavior doesn't make sense and I don't see it documented anywhere.
Michael Kelley
+1  A: 

I had to over come this same exact problem (but on the compact framework) where the BeforeSelect event isn't exposed ( I was bummed).

But think got a fairly elegent solution and hope might help others!!

I made a derived TreeView control (so could select multiple items at once), but will also corrects the "auto" selection of the first node on getting FOCUS.

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

I then overrode the event handlers as such:

/// <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;                                   
}