Как правильно привязать всплывающее окно к ToggleButton?

Я пытаюсь сделать что-то, что кажется относительно простым и логичным с уровня пользовательского интерфейса, но у меня есть одна ошибка, которая очень раздражает. У меня есть ToggleButton, и я пытаюсь показать Popup, когда кнопка переключается и скрывает Popup, когда кнопка переключается. Popup также скрывается, когда пользователь нажимает на него.

Все работает как ожидалось со следующим XAML, за исключением случаев, когда я нажимаю кнопку переключения после отображения Popup, исчезает Popup в течение секунды секунды.

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

Любая помощь приветствуется. Спасибо.

    <ToggleButton x:Name="TogglePopupButton" Content="My Popup Toggle Button" Width="100" />

    <Popup StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=TogglePopupButton, Mode=TwoWay}">
        <Border Width="100" Height="200" Background="White" BorderThickness="1" BorderBrush="Black">
            <TextBlock>This is a test</TextBlock>
        </Border>                
    </Popup>

Ответы

Ответ 1

Ответы Stephans имеют тот недостаток, что исчезает желаемое поведение закрытия всплывающего окна, когда оно теряет фокус.

Я решил это, отключив кнопку переключения, когда всплывающее окно открыто. Альтернативой было бы использовать свойство IsHitTestVisible, а не включено:

    <ToggleButton x:Name="TogglePopupButton" Content="My Popup Toggle Button" Width="100"  IsEnabled="{Binding ElementName=ToggledPopup, Path=IsOpen, Converter={StaticResource BoolToInvertedBoolConverter}}"/>
    <Popup x:Name="ToggledPopup" StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=TogglePopupButton, Mode=TwoWay}">
        <Border Width="100" Height="200" Background="White" BorderThickness="1" BorderBrush="Black">
            <TextBlock>This is a test</TextBlock>
        </Border>                
    </Popup>

Конвертер выглядит так:

public class BoolToInvertedBoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is bool)
        {
            bool boolValue = (bool)value;
            return !boolValue;
        }
        else
            return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException("ConvertBack() of BoolToInvertedBoolConverter is not implemented");
    }
}

Ответ 2

Решение без IValueConverter:

<Grid>
    <ToggleButton x:Name="TogglePopupButton" Content="My Popup Toggle Button" Width="100" >
        <ToggleButton.Style>
            <Style TargetType="{x:Type ToggleButton}">
                <Setter Property="IsHitTestVisible" Value="True"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=Popup, Path=IsOpen}" Value="True">
                        <Setter Property="IsHitTestVisible" Value="False"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ToggleButton.Style>
    </ToggleButton>

    <Popup StaysOpen="false" IsOpen="{Binding IsChecked, ElementName=TogglePopupButton, Mode=TwoWay}"
               PlacementTarget="{Binding ElementName=TogglePopupButton}" PopupAnimation="Slide" 
           x:Name="Popup">
        <Border Width="100" Height="200" Background="White" BorderThickness="1" BorderBrush="Black">
            <TextBlock>This is a test</TextBlock>
        </Border>
    </Popup>
</Grid>

Ответ 3

В ToggleButton установите свойство ClickMode="Press" apixeltoofar

Ответ 4

Установите StaysOpen="True" для Popup

Из MSDN:

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

[...]

true, если элемент управления Popup закрывается, когда для свойства IsOpen установлено значение false;

false, если элемент управления Popup закрывается, когда событие мыши или клавиатуры происходит вне элемента управления Popup.