Как в WPF поместить границу вокруг той части окна, которая находится в фокусе?

У меня есть окно с двумя основными областями. Один из них — TextBox внутри ScrollViewer, а другой — TabControl. Я хочу иметь красную рамку вокруг части, которая в данный момент находится в фокусе, поэтому я написал следующий код для этого.

Xaml

<ScrollViewer BorderBrush="Red" 
              BorderThickness="0"
              GotFocus="Border_GotFocus"  
              LostFocus="Border_LostFocus">
    <TextBox/>
</ScrollViewer>
<TabControl BorderBrush="Red" 
            BorderThickness="0"
            GotFocus="Border_GotFocus"  
            LostFocus="Border_LostFocus">
</TabControl>

Код

private void Border_LostFocus(object sender, RoutedEventArgs e)
{
    var control = sender as Control;
    if (control != null)
    {
        control.BorderThickness = new Thickness(0);
    }
}

private void Border_GotFocus(object sender, RoutedEventArgs e)
{
    var control = sender as Control;
    if (control != null)
    {
        control.BorderThickness = new Thickness(2);
    }
}

Проблема в том, что если я нажму на TextBox, он не обновит границу вокруг ScrollViewer. Если я нажимаю на вкладку в TabControl, она обновляет границу, чтобы я мог видеть границу, но не «удалял» ее, когда я нажимал в другом месте. Есть ли лучший способ сделать это?


person juharr    schedule 24.06.2010    source источник


Ответы (2)


Во-первых, я настоятельно рекомендую не использовать код и хранить все это в XAML.

Во-вторых, я бы также рекомендовал использовать для этого Border.

В-третьих, я бы использовал IsKeyboardFocusedWithin в вашем триггере стиля.

<Window.Resources>
    <Style x:Key="FocusedBorder" TargetType="Border">
        <Setter Property="BorderThickness" Value="2"></Setter>
        <Setter Property="BorderBrush" Value="Transparent"></Setter>
        <Style.Triggers>
            <Trigger Property="IsKeyboardFocusWithin" Value="True">
                <Setter Property="BorderBrush" Value="Red"></Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<StackPanel Width="400">
    <ScrollViewer>
        <Border Style="{StaticResource FocusedBorder}">
            <TextBox>
            </TextBox>
        </Border>
    </ScrollViewer>
    <TabControl>
        <TabItem Header="Foo">
            <Border Style="{StaticResource FocusedBorder}">
                <TextBox></TextBox>
            </Border>
        </TabItem>
        <TabItem Header="Bar">
            <Border Style="{StaticResource FocusedBorder}">
                <TextBox></TextBox>
            </Border>
        </TabItem>
    </TabControl>
</StackPanel>
person Adam Sills    schedule 24.06.2010

Принятый ответ не сработал для меня. Однако я нашел способ без использования границы и все равно получаю тот же эффект.

Ниже приведен стиль, используемый для текстового поля.

<Style x:Key="DefaultTextbox" TargetType="{x:Type TextBox}">
    <Setter Property="FontSize" Value="14" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Margin" Value="5 2 10 2" />
    <Setter Property="FontFamily" Value="Arial" />
    <Setter Property="FontStyle" Value="Normal" />
    <Setter Property="BorderThickness" Value="2" />
    <Setter Property="BorderBrush" Value="Transparent" />
    <Style.Triggers>
        <Trigger Property="IsFocused" Value="True" >
            <Setter Property="BorderBrush" Value="#4E82EC" />
        </Trigger>
    </Style.Triggers>
</Style>

Я столкнулся с некоторыми проблемами со стилем. Изначально я указал толщину границы и цвет в триггере. Проблема в том, что когда в поле был текст, он, казалось, прыгал. Чтобы обойти эффект прыжка, нужно объявить толщину границы по умолчанию и установить прозрачную границу, чтобы при изменении цвета в фокусе не было эффекта прыжка.

Затем вам просто нужно установить стиль в текстовое поле:

<TextBox Style="{StaticResource DefaultTextbox}" />

И это эффект, который вы увидите.

Пример того, как выглядит сфокусированное и не сфокусированное текстовое поле

person David Basarab    schedule 30.08.2011