Try to trap for the focus changed events (GotFocus and LostFocus) in Silverlight in a container control; I dare you! 😉 You’ll quickly realize that all the GotFocus and LostFocus events of all the children controls and their children controls fire on the container. This is of course due to event bubbling (which is a good thing). But, it makes it awefully hard to tell when the container itself is getting focus (after not having it) or loosing focus because something outside your container now has it.
For example: Create a StackPanel (MyContainer) with 2 controls in it and put that next to another control (the button)…
<StackPanel>
<StackPanel x:Name=”MyContainer”>
<TextBox/>
<TextBox/>
</StackPanel>
<Button Content=”button3″/>
</StackPanel>
Now put debug statements in MyContainer’s GotFocus and LostFocus events…
Private Sub MyContainer_GotFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyContainer.GotFocus
Diagnostics.Debug.WriteLine("MyContainer_GotFocus")
End Sub
Private Sub MyContainer_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyContainer.LostFocus
Diagnostics.Debug.WriteLine("MyContainer_LostFocus")
End Sub
Hmm, looks like our container lost focus… but it didn’t!? Focus is simply on another child in the same container. The events are firing like this because the children controls are bubbling up their events to the container so it looks like the container is loosing and getting focus each time. So how do we determine if focus has actually been given to a control outside the container or if focus is still inside the container?
The answer is not that hard. all we need to do is determine if at the time the LostFocus event is fired, if the item that has focus is a child of our container. And you can use the System.Windows.Input.FocusManager.GetFocusedElement method to determine which object has focus. I created a nice little IsRelated function to help determine who is a decendent.
Private Shared Function IsRelated(ByVal Child As Object, ByVal Parent As Object) As Boolean
Return Child Is Parent OrElse (TypeOf Child Is FrameworkElement _
AndAlso _
IsRelated(DirectCast(Child, FrameworkElement).Parent, Parent))
End Function
Private HasFocus As Boolean
Private Sub MyContainer_GotFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyContainer.GotFocus
If Not HasFocus Then
HasFocus = True
Diagnostics.Debug.WriteLine("MyContainer_GotFocus")
End If
End Sub
Private Sub MyContainer_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyContainer.LostFocus
If Not IsRelated(System.Windows.Input.FocusManager.GetFocusedElement, _
MyContainer) Then
HasFocus = False
Diagnostics.Debug.WriteLine("MyContainer_LostFocus")
End If
End Sub
And that’s all there is to it. Happy coding!