隐形打开弹出窗口
第二天打这个问题。
要重现,请创建新的WPF应用程序xaml
Some random text Popup
和代码
private void Button_MouseMove(object sender, MouseEventArgs e) { popup.IsOpen = true; }
鼠标hover按钮打开弹出窗口,单击其他位置关闭。 单击按钮有bug:popup是IsOpen == true (可以在复选框上看到或在处理程序中有断点),而它是不可见的。
WTF?
而我的原始问题似乎是IsOpen
设置不是即时的 。 例如,当我尝试在Popup
的MouseMove
事件中将其设置为false
时,我在此期间获得了Button
MouseEnter
和MouseMove
事件。
IsOpen = true;
与将其设置为true
相同,有2(!)个MouseMove
事件发生,将此行放入事件处理程序以查看它
System.Diagnostics.Trace.WriteLine("M");
在VS的输出窗口中将有2 M,而Popup
(当StayOpen=false
)假设捕获鼠标事件并且确实如此,但不是立即 。
有人可以解释一下它发生了什么吗? 我希望在 (或之后不久?如何检查这是否属实?)设置IsOpen
时不会发生任何事件。 已经尝试了很多东西: Dispatcher.InvokeAsync
,变量,计时器等。
我认为你对异步假设是正确的。 在焦点丢失期间, IsOpen
的值设置为false,但按钮的MouseMove
会触发再次将其设置为打开。 然后内部的一些奇怪的魔法破坏了代码。
根据您的需要,我找到了2种可能的解决方案:
- 弹出窗口关闭后显式将
IsOpen
设置为false
(bash异步) - #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}"
好吧,当您按下按钮时(即使使用空格键),也会调用MouseMove
和MouseEnter
,因此这会导致Popup
IsOpen
尝试关闭同时将IsOpen
设置为true时的情况。 简单的解决方案可能是将这两个事件分开。
一种可能的方法是在MouseEnter
hover在给定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
不应多次打开(包括按下按钮的时间)。