【问题标题】:WPF Popup hiding problemWPF Popup 隐藏问题
【发布时间】:2011-01-20 23:48:43
【问题描述】:

假设您有一个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 for Popup 和 .IsChecked for ToggleButton。 一切正常,但是当您打开Popup 并在边界外单击时,问题就来了。 Popup 将被关闭,但 ToggleButton 保持选中状态

您不能在PopupOnClosed Handler 中设置ToggleButton.IsChecked = false,因为当您点击ToggleButton 关闭Popup 时,Popup 会自行关闭,设置ToggleButton.IsChecked = false 但同时您点击ToggleButton,它尝试再次打开Popup。所以你不能关闭它。

第一次切换按钮点击:

-> ToggleButton IsChecked = true

第二次切换按钮点击:

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

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

请问你是怎么解决这个问题的?

已编辑:

在 MyWindow.XAML 中尝试这个并添加依赖属性 IsDropDownOpen 请在后面的代码中:

<Grid>
        <ToggleButton x:Name="PART_OpenToggleButton"
                      Focusable="False"                          
                      Height="20"
                      Width="50"
                      IsChecked="{Binding ElementName=TestWindow, Mode=TwoWay, Path=IsDropDownOpen}">
            <Grid>

                <Popup x:Name="PART_PopupControl"
                       Width="100"
                       Height="100"
                       StaysOpen="False"
                       Focusable="False"
                       VerticalAlignment="Bottom"
                       IsOpen="{Binding ElementName=TestWindow, Path=IsDropDownOpen}"
                       PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton, AncestorLevel=1}}">                  
                </Popup>
            </Grid>
        </ToggleButton>
    </Grid>

public bool IsDropDownOpen
        {
            get { return (bool)GetValue(IsDropDownOpenProperty); }
            set { SetValue(IsDropDownOpenProperty, value); }
        }        
        public static readonly DependencyProperty IsDropDownOpenProperty =
            DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(Window), new UIPropertyMetadata(false));

【问题讨论】:

标签: wpf popup hide togglebutton


【解决方案1】:

我会将这两个人绑定到 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>

希望这会有所帮助,

干杯,安瓦卡。

【讨论】:

  • 我已经尝试过这种方法,问题是这样的:第一个 ToggleButtonClick: >> ToggleButton IsChecked = true ------ 2md ToggleButtonClick: >> ToggleButton IsChecked = false >> ToggleButton IsChecked = true ------- 因此,如果您在弹出窗口打开时单击切换按钮,它会闪烁但保持打开状态。
【解决方案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">

【讨论】:

  • 哦,好吧.. 谜团已经揭晓。 ClickMode="Press" 是使它工作的属性!谢谢!
  • 我还有 1 个问题:如何确保在弹出窗口外部单击或移动整个窗口时自动关闭?
  • 嗨@PaN1C_Showt1Me,你最后是怎么解决这个问题的?使用“ClickMode=Press”上面的解决方案,我看到了与在弹出窗口外部单击时保持打开状态相同的问题?
  • 说实话..我仍然没有合适的解决方案。
【解决方案3】:

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

使用以下类将允许在按下切换按钮之前处理单击。弹出窗口因单击而关闭,但随后会处理单击,因此不会触发 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;
    }
}

【讨论】:

  • 这终于解决了我的问题,是我认为最简单的解决方案。
【解决方案4】:

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

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

【讨论】:

  • 当其他修复都不起作用时,这对我有用。
【解决方案5】:

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

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

我不使用切换按钮来节省内存,但我认为关键问题是相同的。在您单击它的那一刻,toggleButton 已经是 false。

我的示例弹出窗口是这样定义的:

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

如果您点击放置目标 - 这是“打开按钮”,弹出窗口关闭,同时按钮的点击事件被处理,但 popup.IsOpen 属性已经为“假” - 所以它被打开再次。

我为解决这个问题所做的是订阅弹出窗口“关闭”事件,节省了时间 - 阻止重新打开一秒钟。

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;
}

【讨论】:

    【解决方案6】:

    要防止通过单击背景关闭弹出窗口,请插入填充内容。

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

    <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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-17
      • 2021-07-19
      • 1970-01-01
      • 2016-04-26
      • 2013-10-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多