Why does ListBoxItem require Focus() to get selected

2,739 views
Skip to first unread message

Pavan Podila

unread,
Apr 3, 2009, 1:29:37 PM4/3/09
to WPF Disciples
I have been trying to select a ListBoxItem which had its Focusable
property set to true. After some Reflector-ing, I realized this cannot
be done, since ListBoxItem explicitly checks for Focus() before it
sets the IsSelected flag. Here is the snippet from Reflector

ListBoxItem.cs
--------------------
private void HandleMouseButtonDown(MouseButton mouseButton)
{
if (Selector.UiGetIsSelectable(this) && base.Focus())
{
ListBox parentListBox = this.ParentListBox;
if (parentListBox != null)
{
parentListBox.NotifyListItemClicked(this, mouseButton);
}
}
}


Can someone explain what is the role of Focus for selecting an item ?
I think this is totally unnecessary.


Eric Burke

unread,
Apr 3, 2009, 1:34:37 PM4/3/09
to wpf-di...@googlegroups.com

This isn't checking for whether it has focus; it's trying to focus the keyboard on the ListBoxItem.  If that is prevented for some reason, it doesn't select the item.  It probably has to do with all the focus craziness in WPF with focus scopes and such.

Pavan Podila

unread,
Apr 3, 2009, 1:42:56 PM4/3/09
to WPF Disciples
Right, what I meant was "Is there a need to Focus() in order to select
an item?". This is causing a headache already in solving some issues.

Pavan Podila

unread,
Apr 3, 2009, 1:54:28 PM4/3/09
to WPF Disciples
Ok I was able to solve my problem using the classic
Dispatcher.BeginInvoke() approach. In my custom control I had to shift
focus from the ListBoxItem to a TextBox. The focus should shift
whenever someone double-clicks an item in the ListBox.

Previously, I used to set the focus on the TextBox in the ListBox's
double-click event handler. That of course, doesn't work. Now I make a
deferred call to set the focus, on a DispatcherPriority.Background and
that solves the issue.

FYI for someone facing a similar problem: Dispatcher.BeginInvoke is
your faithful friend.


- Pavan

Eric Burke

unread,
Apr 3, 2009, 1:54:55 PM4/3/09
to wpf-di...@googlegroups.com

Ah, sorry; I misunderstood.

Digging into Keyboard.Focus(), somewhere in KeyboardDevice.TryChangeFocus it raises the PreviewLostFocus event to the thing that currently has focus.  That thing has the ability to mark the event as handled which prevents further processing of it and effectively disallows the focus change.

Once you click on a list box item, generally you assume the list box is focused so that you can use the keyboard to move the selection from item to item.   So maybe the Focus() check is to prevent a selection change without the ability to move the arrows and change focus.

I'm just guessing here. ;)

Pavan Podila

unread,
Apr 3, 2009, 2:24:24 PM4/3/09
to WPF Disciples
Eric,
That could be a possible reason although I think relying on
Focus to do selections is not a good thing. I could still use the
mouse and just click on an item and have it selected. It doesn't have
to check for focus. I think focus comes into play if you are using
Keyboard to do navigation. Selections via Mouse should be allowed
without having focus. That's just my opinion.

David Anson

unread,
Apr 3, 2009, 2:34:39 PM4/3/09
to wpf-di...@googlegroups.com
It's been a while since I did the port of WPF's ListBox to Silverlight (for SL2 B1), but I do still occasionally have nightmares about trying to get the focus behavior right with the reduced API set that Silverlight had... :| Specifically, ListBox maintains some very specific behaviors as you tab into and out of the control. Possibly relevant here is the fact that focus typically goes directly to the selected item. I haven't reviewed the code, but I do recall adding that same Focus call and I'm wondering if its tied to the overall ListBox focus story rather than being there specifically to give you a hard time during item selection... :)

Pavan Podila

unread,
Apr 3, 2009, 2:43:19 PM4/3/09
to WPF Disciples
Could be the later :)

After surveying other list-based controls, I found that the call to
Focus() exists in every MouseLeftButtonDown event handler.

Here's one from MenuItem:
---------------------------
private void FocusOrSelect()
{
if (!base.IsKeyboardFocusWithin)
{
base.Focus();
}
if (!this.IsSelected)
{
this.IsSelected = true;
}
if (this.IsSelected && !this.IsHighlighted)
{
this.IsHighlighted = true;
}
}




This one from TreeViewItem.cs
------------------------------
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (!e.Handled && base.IsEnabled)
{
if (base.Focus())
{
e.Handled = true;
}
if ((e.ClickCount % 2) == 0)
{
this.IsExpanded = !this.IsExpanded;
e.Handled = true;
}
}
base.OnMouseLeftButtonDown(e);
Reply all
Reply to author
Forward
0 new messages