How To: Send focus directly to a CheckBox in a TreeViewItem

2,546 views
Skip to first unread message

Josh Smith

unread,
Jul 30, 2008, 2:41:42 PM7/30/08
to wpf-di...@googlegroups.com
Hey all,

I have a WPF programming question for you all.  I just can't find a way to do this, even after trying several hacks.  Suppose I have a TreeView where items should all contain CheckBoxs.  I want it so that the user can easily navigate through the tree and press Spacebar to check/uncheck an item's CheckBox.  The problem is with input focus.  I find that the TreeViewItems want to take focus first, requiring me to press an arrow key twice to bring focus to the contained CheckBox.  I tried setting Focusable on the ItemContainerStyle to false, but then the keyboard navigation does not work properly.  I also tried writing some code that handles GotFocus and GotKeyboardFocus of all TreeViewItems and then use FindName to get at the CheckBox and give it focus.  This doesn't work either, because focus never leaves the first CheckBox.

Here's the XAML I am using:
<TreeView ItemsSource="{Binding}">
  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Children}">
      <CheckBox
        x:Name="chk"
        Content="{Binding Name}"
        IsChecked="{Binding IsChecked}"
        />
    </HierarchicalDataTemplate>
  </TreeView.ItemTemplate>
</TreeView>

Anyone ever figured this out before?  If so, what's the trick? This seems like it should be a simple XAML-only solution, but I can't figure it out!  :(

Thanks,
Josh

Pavan Podila

unread,
Jul 30, 2008, 3:43:35 PM7/30/08
to wpf-di...@googlegroups.com
Focus management with TreeView and List based controls is pretty tricky and one of the big pain points in WPF. I still don't have a good hold on this topic. I had done something similar earlier just that my template for the TreeViewItem was more complex and had more controls. However due to lack of time, we decided to provide only mouse support (Sucks .. but that was how it went).
--
the approach, rather than the solution
...o0O0o...
http://blog.pixelingene.com

Josh Smith

unread,
Jul 30, 2008, 3:46:21 PM7/30/08
to wpf-di...@googlegroups.com
Thanks Pavan.  Of course, that isn't the answer I was hoping for!  :)  Oh well, it seems I've got my work cut out for me (unless someone can come to the rescue...).

josh

Josh Smith

unread,
Jul 30, 2008, 3:47:15 PM7/30/08
to wpf-di...@googlegroups.com
Hey JG!  This thread is another one to add to your "what we should simplify" list... ;)

Pavan Podila

unread,
Jul 30, 2008, 4:01:09 PM7/30/08
to wpf-di...@googlegroups.com
BTW, did you try calling MoveFocus() on the element that has focus with a TraversalRequest of Down/Up. Keyboard.FocusedElement should get you the current element. This is a pretty manual way and not Xaml based (although if you can get this working you could make it into an attached property).

Josh Smith

unread,
Jul 30, 2008, 4:03:43 PM7/30/08
to wpf-di...@googlegroups.com
Yes I tried that, but that didn't work either.  It is amazing how difficult this is.  It should be dead simple, in my opinion.

Pavan Podila

unread,
Jul 30, 2008, 4:04:41 PM7/30/08
to wpf-di...@googlegroups.com
Let me know if you figure it out ... I'd love to hear !

Josh Smith

unread,
Jul 30, 2008, 4:05:25 PM7/30/08
to wpf-di...@googlegroups.com
Hey, you stole my role in this thread!!  :D

Pavan Podila

unread,
Jul 30, 2008, 4:07:23 PM7/30/08
to wpf-di...@googlegroups.com
Sorry ...all yours :)) I am just equally curious as I know the amount of time I wasted (researched)

Josh Smith

unread,
Jul 30, 2008, 4:07:57 PM7/30/08
to wpf-di...@googlegroups.com
It's all good, Pavan.  Thanks for your help!!

Josh Smith

unread,
Jul 30, 2008, 6:25:59 PM7/30/08
to wpf-di...@googlegroups.com
I found a solution, but it sucks.  I make the CheckBox Focusable=False, hook up a custom command on my TreeView that is triggered via keygestures of Space and Enter, and the execution logic of that command gets the SelectedItem viewmodel object from the tree and toggles it's IsChecked property.  YUCK!

Pavan Podila

unread,
Jul 30, 2008, 8:25:15 PM7/30/08
to wpf-di...@googlegroups.com
Can it get any more convoluted ?! What if I throw in a few more controls into my TreeViewItem ... that should probably cause annihilation.

Dr. WPF

unread,
Jul 30, 2008, 8:29:40 PM7/30/08
to wpf-di...@googlegroups.com

Sorry I'm so late to the party, Josh.

I faced the same issue a while back and actually implemented a solution in which I used a static class called VirtualToggleButton to expose attached properties that would turn any input element (a TreeViewItem, for example) into a toggle button.  In your case, the markup would look like this:

<TreeView ItemsSource="{Binding}">
  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Children}">

      <CheckBox Focusable="False"


        x:Name="chk"
        Content="{Binding Name}"
        IsChecked="{Binding IsChecked}"
        />
    </HierarchicalDataTemplate>
  </TreeView.ItemTemplate>

  <TreeView.ItemContainerStyle>
    <Style TargetType="{x:Type TreeViewItem}">
      <Setter Property="dw:VirtualToggleButton.IsVirtualToggleButton" Value="True" />
      <Setter Property="dw:VirtualToggleButton.IsChecked" Value="{Binding
IsChecked}" />
    </Style>
  </TreeView.ItemContainerStyle>
</TreeView>

I guess the en vogue term for this type of thing is "attached behavior".  (Thank you Mr. Gossman... you've saved me from the overly wordy description about leveraging an attached property to extend a class in order to add support for yada yada yada...)

When the IsVirtualToggleButton property is attached to the TreeViewItem and set to true, the class monitors the TreeViewItem for input events (mouse clicks or key presses) and responds to those events just like a toggle button.  A spacebar press or mouse click will update the attached IsChecked property.  It even supports the IsThreeState property and raises all the expected toggle button events (Checked, Unchecked, and Indeterminate) on the target element.  (Although, it doesn't include the ButtonBase events or properties... I'm too lazy for that.)

You will still need to set Focusable to false on the CheckBox.  Any solution will likely require that because you'll never want the additional navigation stop for the CheckBox.

I'm happy to send you the code if you'd like.  Just let me know and I'll dig it up.  :-)

> />>
>

Dr. WPF - Online Office at http://www.drwpf.com/blog/


Josh Smith

unread,
Jul 30, 2008, 8:37:12 PM7/30/08
to wpf-di...@googlegroups.com
That's a very awesome idea!  If you can find the code, I'd love to see it.  Thanks Doc!

JohnGossman

unread,
Jul 30, 2008, 8:39:41 PM7/30/08
to WPF Disciples
I'm there for you...

Seriously though, that does seem to me to be the value of patterns:
you can tell somebody what the code does using fewer words.

On Jul 30, 5:29 pm, "Dr. WPF" <a...@drwpf.com> wrote:
>
>    I guess the /en vogue/ term for this type of thing is /"attached  
> behavior".  /(Thank you Mr. Gossman... you've saved me from the overly  

Josh Smith

unread,
Jul 30, 2008, 10:25:06 PM7/30/08
to wpf-di...@googlegroups.com
Hey John,

Any chance this difficulty might be ironed out in a subsequent release of platform?  It's hard to believe that creating a TreeView with checkboxes in the items, which is easy to navigate via the keyboard and mouse, requires so much custom work.  This should be dead simple, in my opinion.  If it takes a Dr. WPF to figure it out, it's way too difficult!  :)

Josh

Mike Brown

unread,
Jul 30, 2008, 10:49:07 PM7/30/08
to wpf-di...@googlegroups.com

Josh Smith

unread,
Jul 30, 2008, 10:57:24 PM7/30/08
to wpf-di...@googlegroups.com
Just in case anyone of is wondering how I finally implemented this hacky, ugly solution, I've attached the project.  Remove the .DOC extension, and then unzip it.  What a hack!  Please tell me there's a much simpler, more elegant way!!
TreeViewWithCheckBoxes.zip.DOC

Josh Smith

unread,
Jul 30, 2008, 11:06:26 PM7/30/08
to wpf-di...@googlegroups.com
I should point out, Dr. WPF's solution is definitely more elegant, but an order of magnitude more complicated.  :)

Dr. WPF

unread,
Jul 31, 2008, 1:42:57 AM7/31/08
to wpf-di...@googlegroups.com

I agree that it would be nice if we could get this behavior by simply styling the existing TreeView/TreeViewItem, but unfortunately, without a multiselect TreeView, that’s not possible.  (hint hint)

Just to follow up for the rest of the group, I've attached a version of Josh’s sample that uses the VirtualToggleButton class that I described earlier.  After adding my existing class to the project, it really was just a matter of pulling out the command bindings and handlers and adding two lines of markup to the container style:

  <Setter Property="dw:VirtualToggleButton.IsVirtualToggleButton" Value="True" />

  <Setter Property="dw:VirtualToggleButton.IsChecked" Value="{Binding IsChecked}" />

(Okay, I might have mucked with the default dataset, but that was just for fun.  J)

There are a few reasons why I like this approach:

·         It’s a write once, use anywhere solution.

·         It provides a pure markup solution that is easily understood by our designers.

·         It has all the sexiness of attached behaviors.

(Btw, if you don’t think attached behaviors are sexy, then clearly you’re attaching the wrong behaviors!)

Quoting "wpf-di...@googlegroups.com" <wpf-di...@googlegroups.com>:

> I should point out, Dr. WPF's solution is definitely more *elegant*, but an

> />>
>

TreeViewWithCheckBoxes.dw.zip.DOC

Marlon Grech

unread,
Jul 31, 2008, 3:34:38 AM7/31/08
to wpf-di...@googlegroups.com
Nice one DOC!!!!! You're the MAN!!!!!! Keep on rocking!



--
Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/
Other Blog - http://dotnetalgos.wordpress.com/

Josh Smith

unread,
Jul 31, 2008, 7:49:19 AM7/31/08
to wpf-di...@googlegroups.com
OK, I'm sold.  Your solution is both more elegant and simpler, considering that it's "write once, use anywhere."  Hey Doc, do you mind if I blog about this, or perhaps write a CodeProject article that has both of us as the authors?

On a side note, you might have noticed that I specifically set the theme of this Window to Royale.NormalColor.  The reason I did that is because there is a bug in the CheckBox theme for Aero and Classic!!  When a CheckBox goes from 'indeterminate' state to 'checked' state in the Aero theme, you need to mouse over the control for the indeterminate state visual to go away.  Also, when Windows is using the Classic theme, the Foreground of the CheckBox is used for the checkmark, which means that you cannot see it when it is selected (and using a light foreground for selection).  That really sucks!!  If I can muster the enthusiasm, I'll log it on Connect...

Josh

Josh Smith

unread,
Jul 31, 2008, 8:17:42 AM7/31/08
to wpf-di...@googlegroups.com
Hey Doc,  I've been reviewing your solution more closely.  This is AWESOME!!  We, I, or you need to publish this, if not only to show people how powerful attached properties and routed events can be!  Very nice...

Josh

Josh Smith

unread,
Jul 31, 2008, 9:00:34 AM7/31/08
to wpf-di...@googlegroups.com
I've fixed up the implementation a bit, so the user can click on the text in the treeviewitem and it won't modify the checkstate.  I also optimized the checkstate verification logic (FooViewModel's IsChecked #region).  The updated copy, which uses the Doc's VirtualToggleButton coolness, is attached.  Just waiting for the good Doctor to give me a thumbs-up to write about this stuff.....  ;)

Josh
TreeViewWithCheckBoxes[JAS].zip.DOC

Pavan Podila

unread,
Jul 31, 2008, 9:29:54 AM7/31/08
to WPF Disciples
Doc, thats a fine use of Attached Properties! I was trying to abstract
this a little more for my own needs since I have a TreeViewItem that
has multiple controls, which may need focus.

In your implementation, you are setting Focusable=false and then using
Bindings to show the checked state. In other words we are implementing
a state-machine for each TreeViewItem. If I had to extrapolate for a
TreeViewItem that has multiple controls like a CheckBox + TextBox, how
would you suggest I go about. Right now I am trying to add more states
to my simple StateMachine for each TreeViewItem and forcing a focus()
on the TextBox ...

Would love to hear your views.

Once again, Great job!!


On Jul 31, 9:00 am, "Josh Smith" <flappleja...@gmail.com> wrote:
> I've fixed up the implementation a bit, so the user can click on the text in
> the treeviewitem and it won't modify the checkstate.  I also optimized the
> checkstate verification logic (FooViewModel's IsChecked #region).  The
> updated copy, which uses the Doc's VirtualToggleButton coolness, is
> attached.  Just waiting for the good Doctor to give me a thumbs-up to write
> about this stuff.....  ;)
>
> Josh
>
> >> *(Btw, if you don't think attached behaviors are sexy, then clearly
> >> you're attaching the wrong behaviors!)*
>
> >> Quoting "wpf-di...@googlegroups.com" <wpf-di...@googlegroups.com
> >> >:
>
> >> > I should point out, Dr. WPF's solution is definitely more *elegant*, but
> >> an
> >> > order of magnitude more complicated.  :)
>
> >> > On Wed, Jul 30, 2008 at 10:57 PM, Josh Smith <flappleja...@gmail.com>
> >> wrote:
>
> >> >> Just in case anyone of is wondering how I finally implemented this
> >> hacky,
> >> >> ugly solution, I've attached the project.  Remove the .DOC extension,
> >> and
> >> >> then unzip it.  What a hack!  Please tell me there's a much simpler,
> >> more
> >> >> elegant way!!
>
> >> >> Josh
>
> >> >>> On Wed, Jul 30, 2008 at 10:25 PM, Josh Smith <flappleja...@gmail.com
> >> >wrote:
>
> >> >>>> Hey John,
>
> >> >>>> Any chance this difficulty might be ironed out in a subsequent
> >> release of
> >> >>>> platform?  It's hard to believe that creating a TreeView with
> >> >>>> checkboxes in
> >> >>>> the items, which is easy to navigate via the keyboard and mouse,
> >> >>>> requires so
> >> >>>> much custom work.  This should be dead simple, in my opinion.  If
> >> >>>> it takes a
> >> >>>> Dr. WPF to figure it out, it's way too difficult!  :)
>
> >> >>>> Josh
>
> >> >>>> On Wed, Jul 30, 2008 at 8:39 PM, JohnGossman <gossmans...@gmail.com
> >> >wrote:
>
> >> >>>>> I'm there for you...
>
> >> >>>>> Seriously though, that does seem to me to be the value of patterns:
> >> >>>>> you can tell somebody what the code does using fewer words.
>
> >> >>>>> On Jul 30, 5:29 pm, "Dr. WPF" <a...@drwpf.com> wrote:
>
> >> >>>>> >    I guess the /en vogue/ term for this type of thing is
> >> /"attached
> >> >>>>> > behavior".  /(Thank you Mr. Gossman... you've saved me from the
> >> overly
>
> >> >>>>> > wordy description about leveraging an attached property to extend
> >> a
> >> >>>>> > class in order to add support for yada yada yada...)
>
> >> > />>
>
> >> Dr. WPF - Online Office athttp://www.drwpf.com/blog/
>
>
>
>  TreeViewWithCheckBoxes[JAS].zip.DOC
> 16KDownload

Dr. WPF

unread,
Jul 31, 2008, 10:20:49 AM7/31/08
to wpf-di...@googlegroups.com

Thumbs up.  Publish away!  :-D

You are the Code Project master, my friend!  If you wait for me, it'll likely be another week.  :-s

>>> *(Btw, if you don't think attached behaviors are sexy, then clearly
>>> you're attaching the wrong behaviors!)*

Dr. WPF

unread,
Jul 31, 2008, 11:01:30 AM7/31/08
to wpf-di...@googlegroups.com

Hey Pavan,

Yes, this approach is really a way to turn the TVI, itself, into a CheckBox.  The CheckBox just becomes a way to visualize the checked state and to support toggling via the mouse.  (The attached property adds a mouse click handler, but that won't get called in this scenario because TVI has a class handler that marks the bubbled mousedown event as handled.)

In your scenario, you would have to decide if you really want the TVI, itself, to be so strongly associated with a single control in the TVI.  Once you have more than one child control, this provides an odd user experience.

Moving focus programmatically is always a hard thing because you have to think about all the possible user expectations.  I'm not sure you can solve it with a one-size-fits-all solution.

For example, if you have a TextBox in your TVI, the user may still expect the up and down arrow keys to move them between TVIs.  If you need to support this, then you'd have to handle tunneled key events and move focus programmatically.  And although you might want this behavior in one app, you might not want it in another app (where you might have a multiline text control).

If you really do want to move focus, then you are probably getting to the point where I'd recommend deriving your own TVI (and your own TreeView that uses your custom TVI as its item container).  Attached event handlers only get called after class handlers, so there's only so far you can take them.  You may find that you need to override behavior of the base TVI class.

If you have a simple sample that illustrates what you are doing, I can take a look, but again, I would hesitate to propose a generic solution because other scenarios will likely break the model.

You could definitely come up with a custom TreeView class (and TVI class) that provides configurable properties to help the user establish the correct navigation experience.  Of course, at some point, such a solution starts to overcomplicate the matter.  In many cases, the developer can get the right experience by simply changing the KeyboardNavigation attached properties on the ItemsControl.

Cheers,
-dw

Pavan Podila

unread,
Jul 31, 2008, 1:27:55 PM7/31/08
to WPF Disciples
Thanks a lot Doc! I think I got my answer with the custom TVI. I could
bake my state + focus into a custom TVI rather than creating an
external StateMachine. I am still in prototyping stage so I am not
sure if the interaction I have will be final. It is going through some
changes as I write. But looks like the custom TVI could be a sound
option for my scenario.

I am using the TV since I have a fixed 3-level representation of data.
I was thinking of creating a custom ItemsControl but was resisting it
since I could hammer a TV to fit my needs. I will try to share some
code once I have something concrete.

BTW, Have you ever come across a good use-case for the FocusScope. I
am still not sure when/where to apply this idea. Can you share some
wisdom on that :)

Thanks again for your insight!
> >> >> Dr. WPF - Online Office athttp://www.drwpf.com/blog/[1]
>
> >>  TreeViewWithCheckBoxes[JAS].zip.DOC
> >> 16KDownload
>
>    Dr. WPF - Online Office athttp://www.drwpf.com/blog/[3]
>
> Links:
> ------
> [1] athttp://www.drwpf.com/blog/
> [2]http://groups.google.com/group/wpf-disciples?hl=en
> [3]http://www.drwpf.com/blog/

Andrew

unread,
Jul 31, 2008, 2:04:54 PM7/31/08
to wpf-di...@googlegroups.com

I've worked with focusscopes so I can chime in here if its ok. I believe the only intrinsic focusscopes are the Window, Toolbar, and Menu. We used it in our ribbon as well. Basically a focusscope maintains its own focusedelement. I originally thought this was analogous to how a winforms containercontrol (i.e. usercontrol and form) had its own ActiveControl but its really not. The wpf framework makes some assumptions/behaviors based on the focusscope. The Toolbar and Menu are focusscopes so that they can have keyboard focus without losing/manipulating the real/logically focused element that is on your window. So if you have a menu open and close it, focus should really be moved back in the textbox or whatever you had focus in within the main window. There are several implications when you make something a focus scope. First, when something calls Keyboard.Focus(null) - which things like the Button do when clicked or more accurately when it loses capture and its not in the "main" focusscope - the framework tries to shift focus to the focused element of the "main" focusscope. I could be wording it slightly improperly but that's the basic gisc. Second, as routedcommands are bubbled up the element tree, when they hit a focusscope, the command manager reroutes the command to start at the focusedelement of the parent focusscope. This is how come a command on a button in a toolbar button or menu can get routed to the textbox that had focus on the window. So unless you're making something that is essentially a toolbar/menu type element, you really do not want to make the element a focus scope.

 

-Andrew

Josh Smith

unread,
Jul 31, 2008, 2:08:13 PM7/31/08
to wpf-di...@googlegroups.com
I've been wondering about that for a while now.  Thanks for clearing it up, Andrew!  Very interesting...

Pavan Podila

unread,
Jul 31, 2008, 2:17:56 PM7/31/08
to WPF Disciples
Thanks for sharing that Andrew. If I understand correctly, FocusScope
is useful when you are switching focus between different top-level
components in a window. By making these top-level components as a
FocusScope you can ensure that the right element retains/regains
focus ??
> ...
>
> read more »

Dr. WPF

unread,
Jul 31, 2008, 2:32:41 PM7/31/08
to wpf-di...@googlegroups.com

Andrew's description is quite concise and pretty much covers it.  :-)

The only other place in the framework where FocusScope is used is on ElementHost (for obvious reasons).

FocusScope has been on my list of future blog topics for some time now, but it keeps getting pushed down because it is primarily relevant to control vendors.  Unfortunately, my list is becoming quite long and I've only posted one article in the last couple of months.  :(

Maybe my new community strategy will be to start sending interesting things to Josh! :-D

Andrew

unread,
Jul 31, 2008, 2:34:10 PM7/31/08
to wpf-di...@googlegroups.com

That's what I originally thought in making my original comparison to a winforms containercontrol and while its true that each focusscope maintains its own focused element (in the focusscope dp using focusmanager.focusedelement), as I mentioned there are subtle implications of making something a focusscope that really don't make it suitable (at least in my opinion) for general focus management use. So if you did make an element a focusscope and you had a button within that element, when you click it focus is going to shift out of your focusscope back to the root one. Likewise, if you had a toolbar that was on the main form (i.e. not within your element that's a focusscope) and you click on a button within that toolbar that had a command associated with it (without an explicit target element), the command is going to route up that toolbar and then to the focused element of the main window (since that is its focusscope's parent focusscope) and not get to the focused element of your focusscope. So basically the way its setup, it's really only useful if you're creating a commandsource host type control (i.e. toolbar/menu).

-Andrew

----- Original Message ----
From: Pavan Podila <pavan....@gmail.com>
To: WPF Disciples <wpf-di...@googlegroups.com>
Sent: Thursday, July 31, 2008 2:17:56 PM
Subject: Re: How To: Send focus directly to a CheckBox in a TreeViewItem


Thanks for sharing that Andrew. If I understand correctly, FocusScope
is useful when you are switching focus between different top-level
components in a window. By making these top-level components as a
FocusScope you can ensure that the right element retains/regains
focus ??



> ...
>
> read more »

Josh Smith

unread,
Jul 31, 2008, 2:37:51 PM7/31/08
to wpf-di...@googlegroups.com
I'll gladly write about the things that interest you but you don't have time to write about.  If you're serious about that, let me know in a separate private email and we can discuss further.

josh

Josh Smith

unread,
Aug 1, 2008, 6:10:29 PM8/1/08
to wpf-di...@googlegroups.com
Hi there,

I just published an article that shows how to create a TreeView full of checkboxes.  The solution begs to be simplified, but I think that will require work on Microsoft's behalf.  Even though it's complicated, the solution is quite elegant (thanks to Dr. WPF's VirtualToggleButton!).

Here's the link: http://www.codeproject.com/KB/WPF/TreeViewWithCheckBoxes.aspx

By the way, the end of the article demonstrates a stupid bug in the Aero theme of CheckBox.  Sigh.

Josh
Reply all
Reply to author
Forward
0 new messages