隐形打开弹出窗口

第二天打这个问题。

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

 

和代码

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

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

WTF?

而我的原始问题似乎是IsOpen设置不是即时的 。 例如,当我尝试在PopupMouseMove事件中将其设置为false时,我在此期间获得了Button MouseEnterMouseMove事件。

 IsOpen = true; 

与将其设置为true相同,有2(!)个MouseMove事件发生,将此行放入事件处理程序以查看它

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

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

有人可以解释一下它发生了什么吗? 我希望 (或之后不久?如何检查这是否属实?)设置IsOpen时不会发生任何事件。 已经尝试了很多东西: Dispatcher.InvokeAsync ,变量,计时器等。

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

根据您的需要,我找到了2种可能的解决方案:

  1. 弹出窗口关闭后显式将IsOpen设置为false (bash异步)
  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尝试关闭同时将IsOpen设置为true时的情况。 简单的解决方案可能是将这两个事件分开。

一种可能的方法是在MouseEnterhover在给定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不应多次打开(包括按下按钮的时间)。