Применение прямоугольника фокуса к дочернему элементу

В элементе управления, над которым я сейчас работаю, когда элемент находится в фокусе, прямоугольник фокуса по умолчанию охватывает всю строку и все ее видимые дочерние элементы. Я знаю, как это скрыть. Но я все еще хочу такой индикатор фокуса, когда элемент имеет фокус клавиатуры. Я читал о свойстве IsKeyboardFocused, но это верно и тогда, когда элемент был нажат мышью. Так что я думаю, мне нужно как-то использовать FocusVisualStyle. Но я не могу понять, как.

Вот как выглядит фокус по умолчанию:

введите здесь описание изображения

А вот что должно понравиться:

введите здесь описание изображения

Вот мой код XAML для шаблона элемента управления:

<Border ...>
    <ContentPresenter FocusManager.IsFocusScope="True"
        Content="{TemplateBinding HeaderedContentControl.Header}"
        ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}"
        ContentStringFormat="{TemplateBinding HeaderedItemsControl.HeaderStringFormat}"
        ContentSource="Header"
        Name="PART_Header" .../>
</Border>
<!-- Additional border glare inside the item -->
<Border BorderThickness="1" BorderBrush="#80ffffff" Margin="1"
    SnapsToDevicePixels="True" CornerRadius="2"/>
<!-- Focus rectangle inside the item -->
<Rectangle StrokeDashArray="1 2" StrokeThickness="1" Stroke="Black"
    SnapsToDevicePixels="True" Margin="2"
    Visibility="Hidden" Name="FocusRectangle"
    FocusVisualStyle="{StaticResource FocusStyle}"/>

В моем XAML уже есть прямоугольник фокуса, который по умолчанию невидим. С помощью FocusVisualStyle или чего-то еще это должно быть видно. Но мне это не удалось. Он либо виден при любом фокусе, либо никогда.


person ygoe    schedule 26.07.2012    source источник


Ответы (1)


Я нашел обходной путь для проблемы. Мне это кажется таким же, но я не совсем уверен, что это правильный способ сделать это. Я использую FocusRectangle сверху и забочусь о том, чтобы показать и скрыть его.

Вот триггер, который управляет видимостью прямоугольника фокуса:

<!-- Show the focus rectangle when the item is focused -->
<MultiTrigger>
  <MultiTrigger.Conditions>
    <Condition Property="Controls:TreeViewExItem.IsKeyboardMode" Value="True"/>
    <Condition Property="Controls:TreeViewExItem.IsFocused" Value="True"/>
  </MultiTrigger.Conditions>
  <Setter TargetName="FocusRectangle" Property="Visibility" Value="Visible"/>
</MultiTrigger>

Затем я добавил новое свойство в TreeViewExItem, которое указывает, был ли последний ввод данных с помощью мыши или клавиатуры. Это может быть расширено до сенсорного экрана или стилуса, но у меня нет таких устройств для тестирования.

public static DependencyProperty IsKeyboardModeProperty =
    DependencyProperty.Register(
        "IsKeyboardMode",
        typeof(bool),
        typeof(TreeViewExItem),
        new FrameworkPropertyMetadata(false, null));

public bool IsKeyboardMode
{
    get
    {
        return (bool) GetValue(IsKeyboardModeProperty);
    }
    set
    {
        SetValue(IsKeyboardModeProperty, value);
    }
}

Это свойство передается каждому элементу из родительского элемента управления через привязку:

<!-- Pass on the TreeViewEx' IsKeyboardMode value to each item because
  we couldn't access it otherwise in the triggers -->
<Setter Property="IsKeyboardMode"
  Value="{Binding (Controls:TreeViewEx.IsKeyboardMode),
    RelativeSource={RelativeSource
      AncestorType={x:Type Controls:TreeViewEx}}, Mode=OneWay}" />

То же свойство IsKeyboardMode добавляется в родительский элемент управления TreeViewEx, и вот моя магия:

protected override void OnPreviewKeyDown(KeyEventArgs e)
{
    base.OnPreviewKeyDown(e);
    if (!IsKeyboardMode)
    {
        IsKeyboardMode = true;
        //Debug.WriteLine("Changing to keyboard mode from PreviewKeyDown");
    }
}

protected override void OnPreviewKeyUp(KeyEventArgs e)
{
    base.OnPreviewKeyDown(e);
    if (!IsKeyboardMode)
    {
        IsKeyboardMode = true;
        //Debug.WriteLine("Changing to keyboard mode from PreviewKeyUp");
    }
}

protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
    base.OnPreviewMouseDown(e);
    if (IsKeyboardMode)
    {
        IsKeyboardMode = false;
        //Debug.WriteLine("Changing to mouse mode");
    }
}

Это реагирует на события предварительного просмотра клавиатуры и мыши, чтобы установить соответствующий режим ввода. Только если последний ввод был сделан с клавиатуры, прямоугольник фокуса виден.

person ygoe    schedule 31.07.2012