WPF Popup隐藏问题

时间:2010-02-25 12:26:40

标签: wpf popup hide togglebutton

假设您有一个ToggleButton用于打开Popup,与ComboBox等所有已知元素的行为相同。

...这是代码:

<ToggleButton x:Name="PART_OpenToggleButton"
    Focusable="False"   
    IsChecked="False"
    Template="{StaticResource MyToggleButton}"> 
    <Grid>                                           
        <Popup x:Name="PART_PopupControl"
               Style="{StaticResource MyPopupStyle}"
               StaysOpen="False"
               VerticalAlignment="Bottom"
               IsOpen="False"
               PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton, AncestorLevel=1}}" />
    </Grid>
</ToggleButton>

然后在后面的代码中,IsOpen使用PopupIsChecked使用。ToggleButton。 一切正常,但是当您打开Popup并在边框外单击时问题就会到来。 Popup将被关闭但ToggleButton 仍会被选中

您无法在PopupOnClosed的{​​{1}}处理程序中进行设置,因为当您点击ToggleButton.IsChecked = false关闭ToggleButton时,Popup会自行关闭,设置Popup,但是在您点击ToggleButton.IsChecked = false的时间点,再次尝试打开 ToggleButton。所以你无法关闭它。

1st ToggleButtonClick:

Popup

2nd ToggleButtonClick:

-> ToggleButton IsChecked = true

因此,如果在弹出窗口打开时单击切换按钮,它会闪烁但保持打开状态。

请问您如何解决这个问题?

编辑:

在MyWindow.XAML中尝试此操作并添加依赖项属性IsDropDownOpen 在后面的代码中,请:

-> ToggleButton IsChecked = false
-> ToggleButton IsChecked = true

6 个答案:

答案 0 :(得分:3)

我在这篇文章中找到了解决方案:https://stackoverflow.com/a/5821819/651161

使用以下类将允许在按下togglebutton之前处理单击。弹出窗口因点击而关闭,但随后处理了点击,因此它不会触发ToggleButton点击。

public class MyPopup : Popup {
    protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) {
        bool isOpen = this.IsOpen;
        base.OnPreviewMouseLeftButtonDown(e);

        if (isOpen && !this.IsOpen)
            e.Handled = true;
    }
}

答案 1 :(得分:2)

好的,这里有一些适用于我的代码(这些代码是从工作代码中复制粘贴的,其中删除了一些不感兴趣的部分):

以下是类似ComboBox的UserControl的内容:

<ToggleButton x:Name="Button" Height="19"> 
   <Grid>
        <Label Name="DisplayList" Content="Whatever" />
        <Popup Name="SelectionPopup" MinHeight="100" MinWidth="200"
                    StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=Button}">
        </Popup>
     </Grid>
</ToggleButton>

从自定义模板到实际的ComboBox:

<ToggleButton
      Name="ToggleButton"
      Template="{StaticResource ComboBoxToggleButton}"
      Grid.Column="2"
      Focusable="false"
      IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
      ClickMode="Press">
 </ToggleButton>
 <Popup
      Name="Popup"
      Placement="Bottom"
      IsOpen="{TemplateBinding IsDropDownOpen}"
      AllowsTransparency="True"
      Focusable="False"
      PopupAnimation="Slide">

答案 2 :(得分:1)

您可以将Popups StaysOpen属性绑定到Buttons IsMouseOver属性。这样,只要您点击弹出窗口(IsMouseOver = false = StaysOpen)之外的内容,弹出窗口就会关闭,当点击ToggleButtonIsMouseOver = true = StaysOpen)时它会关闭弹出窗口。 这样,即使是弹出窗口外的点击也会被处理。

<ToggleButton x:Name="Toggle" />
<Popup x:Name="Popup" IsOpen="{Binding ElementName=Toggle, Path=IsChecked, Mode=TwoWay}"
StaysOpen="{Binding ElementName=Toggle, Path=IsMouseOver}" />

答案 3 :(得分:1)

在我看来,有两个问题 - 一个是解决问题,弹出窗口内的点击可能会再次根据它在可视化树中的位置进行处理。

第二个问题是 - 通过点击自动关闭 - 每次在弹出窗口外单击时都会发生,并且可以触发其他事件。即使你点击&#34;打开按钮&#34;关闭问题是 - 你不知道在popup.isOpen之前设置了哪个值 - 因为对于打开按钮的click事件处理程序,它总是为false。

我没有使用toggleButton来节省内存,但我认为关键问题是一样的。单击它时,toggleButton已经为假。

我的示例弹出窗口定义如下:

<Popup Placement="Bottom" PopupAnimation="Slide" Name="PART_Popup" VerticalOffset="3" AllowsTransparency="True" StaysOpen="False">

如果您点击展示位置目标 - 这是&#34;打开按钮&#34;弹出窗口关闭,同时处理了按钮的click事件,但是popup.IsOpen属性已经“错误”了。 - 所以它又被打开了。

我要解决的问题是订阅弹出窗口&#34;已关闭&#34;事件,节省了时间 - 阻止重新打开一秒钟。

DateTime? LastClose = new DateTime?();

private void Popup_Closed(object sender, EventArgs e)
{    LastClose = DateTime.Now;    }

public bool AllowReopen
{
    get {
            if ((popup == null) || (popup.IsOpen)) return false; 
            //You cannot open, when the template isn't applied or it is already open

            return !LastClose.HasValue || (DateTime.Now - LastClose.Value) > new TimeSpan(0,0,1) /*1s*/;
        }
}


public void OpenPopup()
{
     if (!AllowReopen) return;

     popup.IsOpen = true;
}

答案 4 :(得分:0)

我会将两个人绑定到ViewModel中的同一个属性。您可以在Toolbox默认模板中找到很好的示例:

<ToggleButton x:Name="OverflowButton"
            FocusVisualStyle="{x:Null}"
            IsEnabled="{TemplateBinding HasOverflowItems}"
            Style="{StaticResource ToolBarHorizontalOverflowButtonStyle}"
            IsChecked="{Binding Path=IsOverflowOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
            ClickMode="Press"/>
    <Popup x:Name="OverflowPopup"
         AllowsTransparency="true"
         Placement="Bottom"
         IsOpen="{Binding Path=IsOverflowOpen,RelativeSource={RelativeSource TemplatedParent}}"
         StaysOpen="false"
         Focusable="false"
         PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
        <theme:SystemDropShadowChrome Name="Shdw" Color="Transparent">
            <Border Background="{StaticResource ToolBarSubMenuBackground}"
                    BorderBrush="{StaticResource ToolBarMenuBorder}"
                    BorderThickness="1">
                <ToolBarOverflowPanel x:Name="PART_ToolBarOverflowPanel"
                                    Margin="2"
                                    WrapWidth="200"
                                    Focusable="true"
                                    FocusVisualStyle="{x:Null}"
                                    KeyboardNavigation.TabNavigation="Cycle"
                                    KeyboardNavigation.DirectionalNavigation="Cycle"
                                    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </Border>
        </theme:SystemDropShadowChrome>
    </Popup>

希望这有帮助,

干杯,安瓦卡。

答案 5 :(得分:0)

要阻止通过单击其背景来关闭弹出窗口,请插入将填充它的内容。

在此示例中,单击未填充的空格将关闭弹出窗口:

<Popup x:Key="MyPop" Width="200" Height="200" StaysOpen="False">            
                <CheckBox Content="abc" />
</Popup>

在此示例中,单击未填充的空格将不会关闭弹出窗口:

<Popup x:Key="MyPop" Width="200" Height="200" StaysOpen="False">
        <StackPanel Background="Red" Width="200" Height="200"> <!--EXTRA PANEL -->
                <CheckBox Content="abc" />
        </StackPanel>
</Popup>