I'm trying to programatically set keyboard focus to a tree view item (under certain conditions). I've tried 2 methods of setting focus, both of which successfully obtain focus on the TreeViewItem
, but lose keyboard focus.
The tree view is bound to a view model:
<TreeView Name="solutionsModel" TreeViewItem.Selected="solutionsModel_Selected"
ItemsSource="{Binding Items, Mode=OneWay}" />
I'm trying to set focus via the TreeViewItem
Selected
routed event:
private void solutionsModel_Selected(object sender, RoutedEventArgs e)
{
if (solutionsModel.SelectedItem != null && solutionsModel.SelectedItem is SolutionViewModel)
{
if (e.OriginalSource != null && e.OriginalSource is TreeViewItem)
{
FocusManager.SetFocusedElement(solutionsModel, e.OriginalSource as TreeViewItem);
}
}
}
I'm trying to set focus on the TreeViewItem
in the ControlTemplate
:
<Style d:IsControlPart="True" TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Bindi开发者_如何学JAVAng IsSelected, Mode=TwoWay}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Trigger.Setters>
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
</Trigger.Setters>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true" />
<Condition Property="IsSelectionActive" Value="false" />
</MultiTrigger.Conditions>
<!--
<MultiTrigger.Setters>
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
</MultiTrigger.Setters>
-->
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Both of these methods get focus, but lose keyboard focus (TreeViewItem.IsSelectionActive
is false). No other element in the window has focus or keyboard focus that I can tell (in a test, I only have one read only textbox on another panel that could get focus). Interestingly, I can get keyboard focus on the (commented out) MultiTrigger
where IsSelectionActive
is false, but of course that forces keyboard focus on the TreeViewItem
at all times.
Is there another way to have a better chance of getting keyboard focus, and what are some conditions where keyboard focus cannot be obtained?
I'd add this as a comment if I could but, why not just have the TreeView
handle the focus and work with the item abstractly using the TreeView.SelectedItem
. The tree view would always be able to know which item was selected when the typing started. If an item was selected then the TreeView
is in focus and you can pipe the keyboard commands through to the item.
There are probably better ways, but I found a way to do this by extending TreeView
and TreeViewItem
, to have a separate NeedsFocus
property to trigger when to set focus.
The tree view:
<local:ModelTreeView x:Name="solutionsModel" ItemsSource="{Binding Items, Mode=OneWay}">
</local:ModelTreeView>
The updated (partial) control template:
<Style d:IsControlPart="True" TargetType="{x:Type local:ModelTreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="NeedsFocus" Value="{Binding NeedsFocus, Mode=TwoWay}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ModelTreeViewItem}">
<ControlTemplate.Triggers>
<Trigger Property="NeedsFocus" Value="true">
<Trigger.Setters>
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"></Setter>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The extended classes:
public class ModelTreeView : TreeView
{
protected override DependencyObject GetContainerForItemOverride()
{
return new ModelTreeViewItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is ModelTreeViewItem;
}
}
public class ModelTreeViewItem : TreeViewItem
{
///--------------------------------------------------------------------------------
/// <summary>This property gets or sets whether the item needs focus.</summary>
///--------------------------------------------------------------------------------
public static readonly DependencyProperty NeedsFocusProperty = DependencyProperty.Register("NeedsFocus", typeof(bool), typeof(ModelTreeViewItem));
public bool NeedsFocus
{
get
{
return (bool)GetValue(NeedsFocusProperty);
}
set
{
SetValue(NeedsFocusProperty, value);
}
}
protected override DependencyObject GetContainerForItemOverride()
{
return new ModelTreeViewItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is ModelTreeViewItem;
}
}
In the view model, NeedsFocus
is set to false whenever IsSelected
is set.
精彩评论