Re: Tree control focus frustration by Stephany
Stephany
Mon Dec 15 02:32:34 CST 2003
I've just had a long battle with this myself.
If you put some code in a GotFocus event handler for the TreeView you will
see that the Treeview does indeed 'grab' the focus back but only if the
focus is transferred to another control while the AfterSelect event handler
is cancelled.
It possibly happens in a similar fashion in other event handlers for the
TreeView but I haven't bothered to test any others.
What is happening is that, while the AfterSelect event handler is active,
after transferring the focus to wherever, the execution point returns to the
AfterSelect event handler and, as far as I can figure out, something in
TreeView decides that it is has lost the focus and grabs it back. This
causes the GotFocus event to fire when the AfterSelect event handler
finishes.
Whether this is by design or not, I have no idea. From my point of view it
is bug. In VB6, if one transferred the focus to another control while the
NodeClick event handler was active, then the VB6 TreeView did not 'grab' the
focus back and I see no reason why the .Net implementation should behave any
differently. If anyone has any more information on this I would be
interested to hear.
I suppose you might say that I am a bit miffed with the AfterSelect event
because it works differently from the NodeClick event in VB6. In VB6 the
NodeClick event fired when you clicked on a node regardless whether that
node was already selected or not. The AfterSelect event only fires when you
click on a node that is not already selected.
The problem for me was how to make the AfterSelect event to behave like the
VB6 NodeClick event and also to solve the 'problem' of the focus being
returned to the TreeView. This is what works for me. It is not very pretty
but it is reliable.
Private m_showform As Form = Nothing
Private Sub tvMenu_AfterSelect(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.TreeViewEventArgs) Handles tvMenu.AfterSelect
If Not IsNothing(e.Node.Tag) Then
Dim f As Form = UseLoadedForm(e.Node.Tag)
Select Case e.Node.Tag()
Case "fProjectMaint"
If IsNothing(f) Then
f = New fProjectMaint
f.MdiParent = Me
f.Show()
m_showform = f
Else
m_showform = f
tvMenu_GotFocus(tvMenu, New System.EventArgs)
End If
Case "fReportParam"
If IsNothing(f) Then
f = New fReportParam
f.MdiParent = Me
f.Show()
m_showform = f
Else
m_showform = f
tvMenu_GotFocus(tvMenu, New System.EventArgs)
End If
End Select
End If
End Sub
Private Sub tvMenu_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles tvMenu.Click
Dim tn As TreeNode =
tvMenu.GetNodeAt(tvMenu.PointToClient(Cursor.Position))
If Not (tn Is Nothing) Then
If tn Is tvMenu.SelectedNode Then
tvMenu_AfterSelect(tvMenu, New
System.Windows.Forms.TreeViewEventArgs(tvMenu.SelectedNode))
Else
tvMenu.SelectedNode = tn
End If
End If
End Sub
Private Sub tvMenu_GotFocus(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles tvMenu.GotFocus
If Not IsNothing(m_showform) Then
m_showform = Nothing
SendKeys.Send("{TAB}")
End If
End Sub
In the Click event handler we determine which node was clicked. If the
control was clicked while the mouse pointer was not on a node (line) then
the result is Nothing. We then determine if the clicked node is currently
selected. If so then execute the code in the AfterSelect event handler
otherwise make the clicked node the selected node thus allowing the
AfterSelect event to fire normally.
In the AfterSelect event handler we do our bit of magic. In this example we
open an MDI Child form if it is not already open. If it is already open we
transfer the focus to it. Either way we set a variable and make sure that
the GotFocus code is executed.
In the GotFocus event, if the variable is set, we reset it and simulate a
press of the Tab key, thus moving the focus back to where we want it.
I do not purport that this is the only 'workaround'.
"Andrew Lighten" <reply@via.newsgroup> wrote in message
news:brjo6m$24rk$1@otis.netspace.net.au...
> Hi;
>
> I've built the guts of an explorer style application in C#. It has a
> tree view on the left showing a series of nodes that are relevant to my
> user, and as they click on each one, the right-hand side of my window
> shows the particular panel that's relevant to the selected node.
>
> I have one minor frustration, however. What I'd like to do is focus on
> the first control within the newly chosen panel. I know which control
> this is, and I can transfer focus to it by Select()'ing it, but once the
> tree control has finished its AfterSelect() event it steals focus back
> again.
>
> I've got a dual monitor setup and I can step through my tree control's
> AfterSelect() event handler. My new panel is selected, completely drawn
> by calling Update(), the first control on the panel is selected and
> focused on and the tree loses focus. Finally, when I step off the end of
> AfterSelect(), focus magically snaps back to the tree.
>
> I'd really like focus to stay on my newly selected panel rather than the
> tree.
>
> (1) Am I fighting a pointless battle here? Should focus stay with the
tree?
>
> (2) If it's not extremely rude to move focus to the new panel and leave
> it there, how do I do it?
>
> Thanks,
> Andrew.
>