问题描述
解决这个问题的第二天.
Second day fighting this issue.
要重现,创建新的 WPF 应用程序 xaml
To reproduce, create new WPF application, 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;
}
鼠标悬停按钮打开弹出窗口,点击其他地方关闭.单击按钮有错误:弹出是 IsOpen == true(可以在复选框上看到或在处理程序中带有断点),而它是不可见的.
Mouseover button to open popup, click elsewhere to close. Click button to have bug: popup is IsOpen == true (can be seen on checkbox or with breakpoint in handler), while it is invisible.
WTF?
我原来的问题是,似乎设置IsOpen
不是即时的.例如,当我尝试在 Popup
的 MouseMove
事件中将其设置为 false
时,我得到 MouseEnter
和 Button
的 MouseMove
事件在此期间触发
And my original problem is, it seems, what setting IsOpen
is not instant. To example, when I try to set it to false
in Popup
's MouseMove
event, then I get MouseEnter
and MouseMove
events of Button
fired right during that
IsOpen = true;
与设置为true
相同,有2个(!)MouseMove
事件发生,将此行放入事件处理程序中查看
Same with setting it to true
, there are 2 (!) MouseMove
events occurs, put this line into event handler to see it
System.Diagnostics.Trace.WriteLine("M");
VS的Output窗口会有2M,而Popup
(当StayOpen=false
时)假设捕捉鼠标事件和会,但不会立即.
There will be 2 M in the Output window of VS, while Popup
(when StayOpen=false
) suppose to capture mouse events and it does, but not immediately.
谁能解释一下这是怎么回事?我不希望在期间(或不久之后?如何检查这是否是真的?)设置IsOpen
发生任何事件.已经尝试了很多东西:Dispatcher.InvokeAsync
、变量、定时器等
Can someone explain me what it going on? I want no events to occurs during (or shortly after? how to check if this is true?) setting IsOpen
. Tried already dozens of things: Dispatcher.InvokeAsync
, variables, timers, etc.
推荐答案
我认为你对异步假设是正确的.在焦点丢失期间,IsOpen
的值设置为false,但按钮的MouseMove
触发将其重新设置为打开状态.里面的一些奇怪的魔法然后破坏了代码.
I think you are right with the asynchronous assumption. During the focus loss, the value of IsOpen
is set to false, but the MouseMove
of the button triggers to set it open again. Some strange magic inside then breaks the code.
根据您的需要,我找到了 2 个可能的解决方案:
2 possible solutions I found, depending on your needs:
- 在弹出窗口关闭后将
IsOpen
显式设置为false
(bash 异步) - #1 + 在弹出期间禁用按钮
IsOpen == true
- Explicitly set
IsOpen
tofalse
, after the popup closed (bash async) - #1 + Disable the button during the popup
IsOpen == true
第一种方法将在单击按钮期间隐藏弹出窗口.第二种方法会伴随着轻微的闪烁 - 当快速单击按钮时 - 但它会保持弹出窗口打开:
The first approach will hide the popup during clicking on the button. The second approach will come along with a slight flickering - when rapidly clicking the button - but it keeps the popup open:
对于第一种方法,使用以下事件处理程序(您可能不会先检查属性):
For the first approach, use the following event handlers (you might not check the property first):
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
并将其以一种方式绑定到弹出窗口:
For the second approach, use a BoolInvertConverter
and bind it one way to the popup:
IsEnabled="{Binding (Popup.IsOpen), ElementName=popup, Converter={StaticResource BoolInvertConverter}, Mode=OneWay}"
这篇关于隐形打开弹窗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!