4

假设您有一个ToggleButton用于打开 a 的,与所有已知元素等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对于Popup和 。IsCheckedToggleButton. 一切正常,但是当您打开Popup并单击边界外时,问题就来了。将Popup关闭,但ToggleButton 保持检查

您不能在PopupOnClosedHandler 中设置ToggleButton.IsChecked = false,因为当您单击ToggleButton关闭 时PopupPopup关闭本身,设置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));
4

6 回答 6

4

我在这篇文章中找到了解决方案: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;
    }
}
于 2013-08-06T07:28:49.700 回答
3

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

这是一个类似于 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">
于 2010-03-02T08:21:56.827 回答
1

您可以将 PopupsStaysOpen属性绑定到 ButtonsIsMouseOver属性。这样,每当您单击弹出窗口 ( ) 之外的内容时,弹出窗口就会关闭,并且在单击( )IsMouseOver = false = StaysOpen时它将关闭弹出窗口。这样,即使是 Popup 之外的点击也会被处理。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}" />
于 2015-03-05T11:27:13.883 回答
1

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

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

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

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

<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;
}
于 2016-09-05T11:53:23.043 回答
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>

希望这可以帮助,

干杯,安瓦卡。

于 2010-02-25T12:37:43.447 回答
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>
于 2018-02-16T08:42:30.547 回答