I am attempting to set the focus to the first button in an ItemsControl that is templated and bound to a BindableCollection NamesList in the ViewModel. In short, I have a set of buttons that are displayed, and I want the first one (top-leftmost button) to have Focus when the panel appears.
The section of my XAML that is relevant is:
<StackPanel Visibility="{Binding IsNamesListVisible, Converter={StaticResource visibilityConverter}}">
<StackPanel.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsNamesListVisible}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding Path=Items[0], ElementName=NamesList}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<ItemsControl x:Name="NamesList" IsTabStop="False" Focusable="False" VerticalAlignment="Top" HorizontalAlignment="Center" MaxWidth="500">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Focusable="False" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="NameButton" Content="{Binding Name}" Margin="10,10,0,10" Width="200" Height="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button x:Name="OtherButton" Content="Other" Margin="10,10,0,10" Width="200" Height="100" />
</StackPanel>
This StackPanel is one of several that are all contained on the same screen, and is made visible when the NamesList is populated in the ViewModel. (The flag 'IsNamesListVisible' is set to TRUE when 'NamesList' is populated.)
I have tried several different approaches, none of which have yielded any results.
I have tried the approach seen above:
<Setter Property="FocusManager.FocusedElement" Value="{Binding Path=Items[0], ElementName=NamesList}"/>
I have tried:
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=NamesList[0]}"/>
And:
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=NamesList}"/>
I have also tried adding a converter (found at: https://social.msdn.microsoft.com/Forums/vstudio/en-US/9551f7c9-a067-4921-9006-fb4ead912e7d/set-focusedelement-to-selected-listboxitem?forum=wpf) to my solution and used it:
Converter:
public class ItemsControlContainerConverter: MarkupExtension, IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ItemsControl items = (ItemsControl)value;
return items.ItemContainerGenerator.ContainerFromIndex(System.Convert.ToInt32(parameter));
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
Setter:
FocusManager.FocusedElement="{Binding ElementName=list, Converter={loc:ItemsControlContainerConverter}, ConverterParameter=0}">
At this point, I believe that all of these methods are only valid if my ItemsControl is fully populated at runtime. I have used the trigger with the FocusManager.FocusedElement property many times and it has always worked without issue, but I have never used it with an ItemsControl before.
Perhaps I'm missing something obvious, but after a day of banging my head on the proverbial wall, I don't see it.
As mentioned previously, I need the top, leftmost button to have Focus when this panel becomes visible. Any suggestions are greatly appreciated.
FocusManager.FocusedElement is an attached property and only accepts UIElement-derived elements that can have focus. You are assigning it a regular CLR element that cannot receive focus.
You need a converter that, according to the first element, will receive the first child from the visual tree of the ItemsControl item.
Without any problem:
You can even change the collection asynchronously, but this will not affect the element selected for focus. In the example, it will always be selected with index [1].