隐形打开弹出窗口

时间:2014-06-30 13:35:47

标签: c# wpf popup

第二天打这个问题。

要重现,请创建新的WPF应用程序xaml

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
    <Button Width="100" Height="100" MouseMove="Button_MouseMove"/>
    <Popup x:Name="popup" StaysOpen="False" AllowsTransparency="True" Placement="Center">
        <TextBlock>Some random text</TextBlock>
    </Popup>
    <CheckBox IsChecked="{Binding (Popup.IsOpen), ElementName=popup}">Popup</CheckBox>
</StackPanel>

和代码

private void Button_MouseMove(object sender, MouseEventArgs e)
{
    popup.IsOpen = true;
}

鼠标悬停按钮打开弹出窗口,单击其他位置关闭。点击按钮有bug:弹出 IsOpen == true (可以在复选框上看到或在处理程序中有断点),而它是不可见的。

WTF?

我原来的问题似乎是设置IsOpen不是即时。例如,当我尝试在false的{​​{1}}事件中将其设置为Popup时,我会收到MouseMoveMouseEnter个事件{{1}在那个

期间被解雇了
MouseMove

与将其设置为Button相同,会发生2(!)IsOpen = true; 个事件,将此行放入事件处理程序以查看

true

VS的输出窗口中将有2 M,而MouseMove(当System.Diagnostics.Trace.WriteLine("M"); 时)假设捕获鼠标事件但确实如此,但是没有立即

有人可以解释一下它发生了什么吗?我希望期间(或之后不久?如何检查这是否属实?)设置Popup。已经尝试过几十件事:StayOpen=false,变量,计时器等。

2 个答案:

答案 0 :(得分:4)

我认为你对异步假设是正确的。在焦点丢失期间,IsOpen的值设置为false,但按钮的MouseMove会触发再次将其设置为打开。然后一些奇怪的魔法打破了代码。

我发现了两种可能的解决方案,具体取决于您的需求:

  1. 在弹出窗口关闭(bash异步)后明确将IsOpen设置为false
  2. #1 +在弹出IsOpen == true
  3. 期间禁用该按钮

    第一种方法是在点击按钮时隐藏弹出窗口。第二种方法会伴随轻微的闪烁 - 当快速点击按钮时 - 但它会保持弹出窗口打开:

    对于第一种方法,请使用以下事件处理程序(您可能不会先检查属性):

    private void Button_MouseMove(object sender, MouseEventArgs e)
    {
        popup.IsOpen = true;
    }
    
    private void Popup_OnClosed(object sender, EventArgs e)
    {
        if (popup.IsOpen)
            popup.IsOpen = false;
    }
    

    对于第二种方法,使用BoolInvertConverter并将其绑定到弹出窗口:

    IsEnabled="{Binding (Popup.IsOpen), ElementName=popup, Converter={StaticResource BoolInvertConverter}, Mode=OneWay}"
    

答案 1 :(得分:2)

好吧,当您按下按钮时,MouseMoveMouseEnter都会被调用(即使使用空格键),这会导致PopupIsOpen尝试关闭时{ {1}}同时设置为true。简单的解决方案可能是将这两个事件分开。

一种可能的方法是在悬停在给定的MouseEnter上时坚持Popup并打开Button一次。就像例子一样:

private Button currentPopupHolder;
private void Button_MouseEnter(object sender, MouseEventArgs e)
{
   var btn = sender as Button;
   if (currentPopupHolder != btn)
   {
      popup.IsOpen = true;
      currentPopupHolder = btn;
   }
}

private void Button_MouseLeave(object sender, MouseEventArgs e)
{
   currentPopupHolder = null;
}

虽然同一Button生成此事件Popup不应多次打开(包括按下按钮的时间)。