I have a button which is in a DataTemplate on the extended toolkit BusyIndicator control. I have a data trigger (and I've tried a style trigger) bound to the visibility of the BusyIndicator control to have the FocusManager set focus to the button when the BusyIndicator is visible.
This does not work. I've also tried to handle the IsVisibleChanged event on the BusyIndicator to set the focus on the button in the code-behind by traversing the visual tree and that did not work either. Is there some special way to set the keyboard focus on a button?

- 166,899
- 29
- 327
- 400

- 6,429
- 7
- 23
- 24
-
1Can you post your template / code – GazTheDestroyer Feb 07 '12 at 14:48
-
After more hours of research I have more information. Traversing the visual tree does find the element (button) I want to focus but no matter what code I use to focus the element (FocusManager or Keyboard focus) it will not focus. I read some article that says if a container is collapsed when the window is shown that the child elements can't be focused when the container if visible. I'm not sure how true this is but if I make the container visible and set the height to 0 the button can be focused in xaml and in code-behind. Why is this? – Brett Mathe Feb 08 '12 at 20:56
2 Answers
I think I have had this same problem. Here is the code I used:
public delegate void SimpleDelegate();
private void grid_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (grid.Visibility == System.Windows.Visibility.Visible)
{
TextBox tb = (TextBox)(sender as Grid).FindName("theTextbox");
tb.SelectAll();
Dispatcher.BeginInvoke(DispatcherPriority.Input, new SimpleDelegate(delegate { tb.Focus(); }));
}
}
This code also selects all the text when the grid containing the textbox is shown.
Maybe there is a better way to do it, but using the Dispatcher to set the focus seemed to work for me.

- 5,060
- 1
- 20
- 20
-
Why do you have to use the Dispatcher to set focus? I don't understand the reason for this. – Brett Mathe Feb 08 '12 at 20:57
-
Honestly, I do not know why it doesn't work without that. I just remembered having the exact problem and doing this to fix it. Using BeginInvoke on the Dispatcher basically says "do this on the UI thread, when you get the chance." Since the VisibleChanged handler is also on the UI thread, it must not be ready to set focus at that point. – Paul Hoenecke Feb 09 '12 at 04:09
-
I finally got around to testing this and yes it does work. Crazy solution but it works. Thanks! – Brett Mathe Feb 14 '12 at 21:46
This SO article describes how you can select the container of an item in an ItemsControl and navigate the tree to select the item you want to alter (in this case focusing it).
Revising my code from below:
public void WhateverMethodForShowingBusy ()
{
//Get a reference to your View
FrameworkElement myView = this.View; // I generally have a reference to the view living on the ViewModel set at construction time
// Get a reference to your ItemsControl - in this example by name
ListBox custListBox = myView.ListBoxName;
// Get the currently selected Item which will be a CustomerViewModel
// (not a DataTemplate or ListBoxItem)
CustomerViewModel cvm = custListBox.SelectedItem;
//Generate the ContentPresenter
ContentPresenter cp = custListBox.ItemContainerGenerator.ContainerFromItem(cvm) as ContentPresenter;
//Now get the button and focus it.
Button myButton = cp.FindName("MyButtonName");
myButton.Focus();
}
The information below is incorrect based on the mistake that IsFocused was a read/write property that would set focus. It is not applicable.
This is another place where MVVM really works well. If you are unfamiliar with MVVM I would highly suggest looking into it. It solves a lot of problems like this and if implemented properly it can make your code much more maintainable.
If you are using an MVVM approach, just host a boolean property (we'll call it IsFocused) on the ViewModel that is sitting behind the DataTemplate. For example we have a Customer class, a CustomerViewModel class which contains an instance of customer, and then your MainViewModel which contains a collection of CustomerViewModels. Your ItemsControl's ItemsSource property is bound to the CustomerViewModels collection, and the DataTemplate button's IsFocused property is bound to the IsFocused property on the CustomerViewModel.
I am unsure of your workflow, but you can essentially do something like so:
public void WhateverMethodForShowingBusy ()
{
//Get a reference to your View
FrameworkElement myView = this.View; // I generally have a reference to the view living on the ViewModel set at construction time
// Get a reference to your ItemsControl - in this example by name
ListBox custListBox = myView.ListBoxName;
// Get the currently selected Item which will be a CustomerViewModel
// (not a DataTemplate or ListBoxItem)
CustomerViewModel cvm = custListBox.SelectedItem;
//Finally set the property.
cvm.IsFocused = true;
}
As with all things in MVVM, be sure that you are implementing INotifyPropertyChanged.

- 1
- 1

- 7,388
- 7
- 51
- 78
-
there is no direct property for isfocused , you would have to do extra work here that you aren't mentioning, you would have to create a custom dependency property IsFocused and either attach it to the button or create special inherited control to use with your viewmodel – tam Feb 07 '12 at 16:07
-
My scenario is just a control with a data template. Not a list. I've tied it with just a stack panel as well to no avail. It seems to have something to do with the container's initial status being collapsed. If the panel is visible first it works with no problems. We changed it to always be visible with a 0 height in the "hidden" state but that feels dirty. – Brett Mathe Feb 09 '12 at 00:57