Dlaczego IsKeyboardFocusWithin zwraca False, gdy kliknę dziecko elementu?

Odpowiedz Nowy wątek
2019-01-10 15:20
0

Mam taki Popup, który reaguje na ToggleButton - gdy button ma IsChecked równe True to się pojawia, a jak False to znika.
Dodatkowo, gdy kliknie się gdziekolwiek indziej w programie, to chciałabym, żeby ToggleButton ustawiał się na False, i żeby w efekcie Popup zniknął. Kod, który działa prawie zgodnie z założeniami:

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition SourceName="Preview" Property="IsKeyboardFocusWithin" Value="False" />
    </MultiTrigger.Conditions>
    <Setter TargetName="Preview" Property="IsChecked" Value="False" />
</MultiTrigger>
<ToggleButton x:Name="Preview" Width="20" Height="20" 
              Cursor="Hand"
              Visibility="Collapsed">
    <Grid>
        <Image Source="{Binding Source={x:Static properties:Resources.PreviewNormal}, Converter={StaticResource BitmapConverter}}"                  
               Width="20" Height="20" HorizontalAlignment="Left" ToolTip="Pokaż podgląd" />

        <Popup x:Name="PreviewPopup"
               AllowsTransparency="True" 
               HorizontalAlignment="Right" HorizontalOffset="10" VerticalOffset="0" 
               PopupAnimation="Fade" Placement="Right" 
               PlacementTarget="{Binding ElementName=Root}"
               DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
            <Popup.Style>
                <Style TargetType="Popup">
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions >
                                <Condition Binding="{Binding ShowPreviewText}" Value="True"/>
                                <Condition Binding="{Binding ElementName=Preview, Path=IsChecked}" Value="True"/>
                            </MultiDataTrigger.Conditions>
                            <MultiDataTrigger.Setters>
                                <Setter Property="IsOpen" Value="True"/>
                            </MultiDataTrigger.Setters>
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </Popup.Style>
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" x:Name="PopupRoot" >
                <Border Background="{StaticResource DefaultBackgroundBrush}" 
                    BorderBrush="{StaticResource DefaultBorderBrush}" 
                    BorderThickness="1" Padding="4"
                    IsHitTestVisible="True"
                    Focusable="False"
                    HorizontalAlignment="Stretch">
                    <ScrollViewer VerticalScrollBarVisibility="Auto"
                                  MaxHeight="200"
                                  MaxWidth="530">
                        <TextBlock Text="{Binding PreviewText}" />
                    </ScrollViewer>
                </Border>
            </StackPanel>
        </Popup>
    </Grid>
</ToggleButton>

Mam jednak problem z jedną sytuacją - gdy użytkownik kliknie wewnątrz Popup'u, to Popup znika... A tego nie chcę. Nie rozumiem, dlaczego tak się dzieje, skoro wg dokumentacji IsKeyboardFocusWithin:

Gets a value indicating whether keyboard focus is anywhere within the element or its visual tree child elements. This is a dependency property.

Rozumiem, że focus ucieka z ToggleButton, ale przecież wciąż znajduje się w dziecku tego elementu, nieprawdaż?
Próbowałam w Border zmienić parametr Focusable na True, jednak efekt działania jest ten sam.

edytowany 1x, ostatnio: aurel, 2019-01-10 15:20

Pozostało 580 znaków

2019-01-11 17:05
0

Próbując wykminić, co się dzieje z focusem, usunęłam wyżej wspomniany MultiTrigger na Preview, a dodałam o taki:

            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition SourceName="PreviewPopup" Property="IsKeyboardFocusWithin" Value="False" />
                </MultiTrigger.Conditions>
                <Setter TargetName="PreviewTextBlock" Property="Background" Value="Red" />
            </MultiTrigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition SourceName="PreviewPopup" Property="IsKeyboardFocusWithin" Value="True" />
                </MultiTrigger.Conditions>
                <Setter TargetName="PreviewTextBlock" Property="Background" Value="Green" />
            </MultiTrigger>

Chciałam zrozumieć, kiedy focus jest w Popupie, a kiedy nie. Niestety, wnioski są takie, że z tego nie idzie nic wywnioskować... Struktura Popupu taka sama, tylko TextBlock zyskał Name="PreviewTextBlock".

  1. Kliknięcie w ToggleButton -> pojawia się Popup, TextBlock jest czerwony
  2. Kliknięcie w Scroll -> TextBlock dalej jest czerwony
  3. Kliknięcie w TextBlock -> TextBlock robi się zielony
  4. Kliknięcie w Scroll -> TextBlock dalej jest zielony
  5. Kliknięcie w dokumencie Worda (te elementy są w TaskPane) -> TextBlock dalej jest zielony
  6. Kliknięcie gdzieś indziej w TaskPane -> TextBlock robi się czerwony

Przypomnę, że moim celem jest, by Popup nie znikał, gdy klikamy w niego, a znikał, gdy klikamy poza nim...

Pozostało 580 znaków

2019-01-11 17:56

Dobra, ostatecznie nic mnie nie obchodzi gdzie jest focus. Usunęłam wszystkie MultiTriggery i opierając się na tej odpowiedzi: https://stackoverflow.com/que[...]ind-a-popup-to-a-togglebutton
Wyciągnęłam Popup z wnętrza ToggleButtona (w przeciwnym wypadku kliknięcie w Popup wyłączało IsChecked na ToggleButton, co wprowadzało dodatkową konfuzję), StayOpen ustawiłam na False i zrobiłam TwoWay Binding łączące IsOpen z IsChecked, oraz na ToggleButton:

IsEnabled="{Binding ElementName=PreviewPopup, Path=IsOpen, Converter={StaticResource InverseBoolConverter}}"

Teraz działa, choć focus dalej jest IMHO zaskakujący, ale już mnie to nie obchodzi ;)

edytowany 1x, ostatnio: aurel, 2019-01-11 17:58

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0