Триггер WPF ListBox не работает для свойства IsFocused - PullRequest
4 голосов
/ 18 ноября 2009

Я хочу оформить свой ListBox и отобразить Border вокруг него. Я хочу скрыть это Border, когда ListBox получает фокус:

<Trigger Property="IsFocused" Value="True">
    <Setter Property="Visibility" TargetName="border" Value="Collapsed"/>
</Trigger>

То же самое, что я использую в TextBox, и оно работает правильно. Почему это Trigger не работает для ListBox?

Изменить:

У меня есть это Style для моего ListBox:

<ControlTemplate TargetType="{x:Type local:ListBox}">
    <Border SnapsToDevicePixels="true" x:Name="Bd" CornerRadius="5"
            Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}" Padding="1">
        <Grid>
            <local:ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </local:ScrollViewer>
            <Border CornerRadius="5" Background="Red" x:Name="border">
                <TextBlock VerticalAlignment="Center" FontWeight="Bold" Foreground="White"
                           Text="{TemplateBinding Message}" FontFamily="Courier New" />
            </Border>
        </Grid>
    </Border>
</DockPanel>
    <ControlTemplate.Triggers>
        <Trigger Property="IsFocused" Value="True">
            <Setter Property="Visibility" TargetName="border" Value="Collapsed"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Background" TargetName="Bd"
                    Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
        </Trigger>
        <Trigger Property="IsGrouping" Value="true">
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Ответы [ 3 ]

5 голосов
/ 18 ноября 2009

У меня также были проблемы с настройкой вашего примера. Я пришел к выводу, что если вы нажмете на ListBoxItem, свойство IsFocused будет False для ListBox, потому что на самом деле фокус имеет ListBoxItem. Вы увидите прокомментированный стиль XAML ниже, пытаясь достичь желаемого эффекта, который не сработал.

Я бы предположил, что закомментированный XAML будет работать, если вы нажмете где-нибудь в пределах ListBox, где не было элементов (то есть не- ListBoxItem пробел внутри ListBox). Редактировать: Только что попробовал, по какой-то причине тоже не работает.

Что сработало, так это создание стиля для всех ListBoxItem объектов внутри ListBox. Этот стиль в основном имеет EventSetters, который соответствующим образом устанавливает свойство BorderBrush MyListBox при запуске.

XAML:

<ListBox Name="MyListBox" DockPanel.Dock="Top" BorderThickness="2">
    <!--<ListBox.Style>
        <Style TargetType="{x:Type ListBox}">
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="2"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.Style>-->
    <ListBox.Resources>
        <Style TargetType="{x:Type ListBoxItem}">
            <EventSetter Event="GotFocus" Handler="ListBoxItem_GotFocus"/>
            <EventSetter Event="LostFocus" Handler="ListBoxItem_LostFocus"/>
        </Style>
    </ListBox.Resources>
    <ListBoxItem>Item 1</ListBoxItem>
    <ListBoxItem>Item 2</ListBoxItem>
    <ListBoxItem>Item 3</ListBoxItem>
    <ListBoxItem>Item 4</ListBoxItem>
</ListBox>

Code-Behind:

private void ListBoxItem_GotFocus(object sender, RoutedEventArgs e) {
    MyListBox.BorderBrush = Brushes.Red;
}

private void ListBoxItem_LostFocus(object sender, RoutedEventArgs e) {
    MyListBox.BorderBrush = Brushes.Black;
}

Надеюсь, это немного помогло!

EDIT: Я не был удовлетворен своим первоначальным ответом (выше), потому что мне нравится декларативно делать вещи, когда я кодирую в WPF (без кода). Я придумал решение, которое использует простые цветовые анимации, которые запускают перенаправленные события GotFocus и LostFocus.

Вот оно:

<ListBox Name="MyListBox" DockPanel.Dock="Top" BorderThickness="2" Height="200">
        <ListBox.BorderBrush>
            <SolidColorBrush Color="Black"/>
        </ListBox.BorderBrush>
        <ListBox.Style>
            <Style TargetType="{x:Type ListBox}">
                <Style.Resources>
                    <Storyboard x:Key="FadeBlack">
                        <ColorAnimation Storyboard.TargetProperty="BorderBrush.Color" 
                                        To="Black" Duration="0:0:0.1"/>
                    </Storyboard>
                    <Storyboard x:Key="FadeRed">
                        <ColorAnimation Storyboard.TargetProperty="BorderBrush.Color" 
                                        To="Red" Duration="0:0:0.1"/>
                    </Storyboard>
                </Style.Resources>
                <Style.Triggers>
                    <EventTrigger RoutedEvent="GotFocus">
                        <BeginStoryboard Storyboard="{StaticResource FadeRed}"/>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="LostFocus">
                        <BeginStoryboard Storyboard="{StaticResource FadeBlack}"/>
                    </EventTrigger>
                </Style.Triggers>
            </Style>
        </ListBox.Style>
        <ListBoxItem>Item 1</ListBoxItem>
        <ListBoxItem>Item 2</ListBoxItem>
        <ListBoxItem>Item 3</ListBoxItem>
        <ListBoxItem>Item 4</ListBoxItem>
    </ListBox>

Удачного кодирования!

РЕДАКТИРОВАТЬ 2: Я посмотрел на ваш обновленный код и увидел, что вы пытались сделать (я думаю). Я нашел эту аккуратную анимацию в Блог Лестера WPF . Вы можете попробовать поместить это в свою <ControlTemplate.Triggers> коллекцию:

<EventTrigger RoutedEvent="ListBox.GotFocus">
    <BeginStoryboard>
        <Storyboard>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="border">
                    <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ListBox.LostFocus">
    <BeginStoryboard>
        <Storyboard>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="border">
                <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" />
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>
0 голосов
/ 29 июня 2014

Попробуйте, это работает.

    <Style.Triggers>
        <EventTrigger RoutedEvent="Control.GotFocus">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Orange" Duration="0:0:0.250"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="Control.LostFocus">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation Storyboard.TargetProperty="Background.Color" To="White" Duration="0:0:0.250"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
0 голосов
/ 24 ноября 2009

Для ListBox IsFocused не обновляется, потому что фокус не переходит к списку, а к области, покрытой списком, означает ItemsPresenter, который содержит ListBoxItems. У меня есть обходной путь к этой проблеме. В обработчике события MouseDown ListBox я вызываю метод Focus (). Он устанавливает для свойства IsFocused значение true и заставляет мой триггер работать.

...