如何正确地将 Popup 绑定到 ToggleButton?

Posted

技术标签:

【中文标题】如何正确地将 Popup 绑定到 ToggleButton?【英文标题】:How do I correctly bind a Popup to a ToggleButton? 【发布时间】:2012-12-24 12:02:06 【问题描述】:

我正在尝试做一些从用户界面级别看起来相对简单和逻辑的事情,但是我有一个非常烦人的错误。我有一个ToggleButton,我试图在切换按钮时显示Popup,并在切换按钮时隐藏PopupPopup 也会在用户点击离开它时隐藏。

除了在显示Popup 后单击切换按钮时,使用以下 XAML 一切都按预期工作,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");
    

【讨论】:

非常聪明。我使用 IsHitTestVisibile 方法是因为我们需要 IsEnabled 其他原因。 这解决了问题,但解决方案显然取决于一些棘手的时机。当我用等效的视图模型绑定替换转换器时,它不再起作用。显然按钮向下设置 IsOpen = false,重新启用 ToggleButton,并且按钮向上触发 ToggleButton。不知道为什么转换器版本有效。我担心当新版本的框架发布或者这个解决方案被以非平凡的方式使用时,时间可能会被淘汰。 @RobertVažan 我已将弹出窗口放入自定义控件中,现在遇到您指定的问题。如果弹出窗口是这个答案给出的外部控件的一部分,它就可以工作。 @RobertVažan 如果您向绑定添加延迟,此解决方案的 ViewModel 版本似乎可以工作:&lt;Popup IsOpen="Binding IsPopupOpen, Delay=10"&gt; 很好的解决方案。但是在模板中使用这些方法时出现问题。因为此模板的每个项目都共享相同的控件名称。有没有办法用RelativeSource做到这一点我自己试过但没有成功。【参考方案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

【讨论】:

乍一看这似乎有效,但是当单击 ToggleButton 不再重新打开 Popup 时,单击其他任何地方突然无法按预期关闭 Popup。我不明白为什么会发生这种情况以及它是否可以修复,但我无法让它工作。【参考方案4】:

为您的Popup设置StaysOpen="True"

来自MSDN:

获取或设置一个值,该值指示 Popup 控件是否关闭 当控件不再处于焦点时。

[...]

true 如果Popup 控件在IsOpen 属性设置为false 时关闭;

false 如果Popup 控件在Popup 控件之外发生鼠标或键盘事件时关闭。

【讨论】:

想要的效果是在焦点丢失时仍然关闭弹出窗口。问题是当您使用ToggleButton 打开Popup,并尝试通过单击ToggleButton 关闭Popup。它将执行StaysOpen="False" 的操作和ToggleButton 的点击导致Popup 关闭然后再次打开。

以上是关于如何正确地将 Popup 绑定到 ToggleButton?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将数据绑定到 Angular2 中的单选按钮?

如何使用 netbeans 轻松地将任何数据库视图绑定到 jtable?

Knockout JS 如何将数据绑定到静态表单元素

如何正确调用Create或者CreateEx函数生成CWnd类派生类的具有WS_POPUP属性的窗口

如何正确地将列表返回到 Xamarin ListView?

如何正确地将 UITextField 添加到 UITableViewCell