Как программно получить фокус клавиатуры на WPF TreeViewItem? - PullRequest
3 голосов
/ 11 мая 2011

Я пытаюсь программно установить фокус клавиатуры на элемент дерева (при определенных условиях).Я попробовал 2 способа установки фокуса, оба из которых успешно получают фокус на TreeViewItem, но теряют фокус клавиатуры.

Древовидное представление привязано к модели представления:

<TreeView Name="solutionsModel" TreeViewItem.Selected="solutionsModel_Selected"
          ItemsSource="{Binding Items, Mode=OneWay}" />

Я пытаюсь установить фокус с помощью перенаправленного события TreeViewItem Selected:

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);
        }
    }
}

Я пытаюсь установить фокус на TreeViewItem в ControlTemplate:

<Style d:IsControlPart="True" TargetType="{x:Type TreeViewItem}">
    <Setter Property="IsSelected" Value="{Binding 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>

Оба эти метода получают фокус, но теряют фокус клавиатуры (TreeViewItem.IsSelectionActive неверно).Никакой другой элемент в окне не имеет фокуса или фокуса клавиатуры, который я могу сказать (в тесте у меня только одно текстовое поле только для чтения на другой панели, которое могло бы сфокусироваться).Интересно, что я могу сфокусировать клавиатуру на (закомментированном) MultiTrigger, где IsSelectionActive ложно, но, конечно, это постоянно заставляет клавиатуру фокусироваться на TreeViewItem.

Есть ли другой способу вас больше шансов получить фокусировку на клавиатуре, и в каких условиях нельзя получить фокусировку на клавиатуре?

Ответы [ 2 ]

3 голосов
/ 11 мая 2011

Я бы добавил это как комментарий, если бы мог, но почему бы просто не TreeView обработать фокус и работать с элементом абстрактно, используя TreeView.SelectedItem. В древовидном представлении всегда можно узнать, какой элемент был выбран при начале набора текста. Если элемент был выбран, то TreeView находится в фокусе, и вы можете направить на него команды клавиатуры.

2 голосов
/ 12 мая 2011

Возможно, есть и лучшие способы, но я нашел способ сделать это, расширив TreeView и TreeViewItem, чтобы иметь отдельное свойство NeedsFocus для запуска, когда нужно установить фокус.

Вид дерева:

    <local:ModelTreeView x:Name="solutionsModel" ItemsSource="{Binding Items, Mode=OneWay}">
    </local:ModelTreeView>

Обновленный (частичный) контрольный шаблон:

<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>

Расширенные классы:

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;
    }
}

В модели представления NeedsFocus устанавливается в значение false, если установлено IsSelected.

...