看不见的打开的弹出框

本文关键字:看不见 | 更新日期: 2023-09-27 18:10:45

抗争第二天

要重新创建新的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不是即时的。例如,当我尝试在PopupMouseMove事件中将其设置为false时,我会在

期间触发ButtonMouseEnterMouseMove事件。
IsOpen = true;

同样设置为true,有2个(!)发生MouseMove事件,将这行放入事件处理程序中查看

System.Diagnostics.Trace.WriteLine("M");

在VS的Output窗口中将有2 M,而Popup(当StayOpen=false)假设捕获鼠标事件并且确实如此,但不是立即

谁能给我解释一下这是怎么回事?我希望在期间(或之后不久)没有事件发生 ?如何检查这是否为真?)设置IsOpen。已经尝试了很多东西:Dispatcher.InvokeAsync,变量,计时器等

看不见的打开的弹出框

我认为你的异步假设是对的。在失焦期间,IsOpen的值被设置为false,但按钮的MouseMove触发将其重新设置为打开。一些奇怪的魔法会打破密码。

根据你的需要,我找到了两个可能的解决方案:

  1. 显式设置IsOpenfalse,在弹出窗口关闭后(bash async)
  2. #1 +在弹出时禁用按钮IsOpen == true

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

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

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

当您按下按钮时(即使使用空格键),MouseMoveMouseEnter都被调用,因此这会导致Popup试图关闭而同时将IsOpen设置为true的情况。简单的解决方案是将这两个事件分开。

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

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不应该被打开超过一次(包括按钮被按下的时间)