第二天打这个问题。
要重现,请创建新的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
时,我会收到MouseMove
和MouseEnter
个事件{{1}在那个
MouseMove
与将其设置为Button
相同,会发生2(!)IsOpen = true;
个事件,将此行放入事件处理程序以查看
true
VS的输出窗口中将有2 M,而MouseMove
(当System.Diagnostics.Trace.WriteLine("M");
时)假设捕获鼠标事件但确实如此,但是没有立即
有人可以解释一下它发生了什么吗?我希望在期间(或之后不久?如何检查这是否属实?)设置Popup
。已经尝试过几十件事:StayOpen=false
,变量,计时器等。
答案 0 :(得分:4)
我认为你对异步假设是正确的。在焦点丢失期间,IsOpen
的值设置为false,但按钮的MouseMove
会触发再次将其设置为打开。然后一些奇怪的魔法打破了代码。
我发现了两种可能的解决方案,具体取决于您的需求:
IsOpen
设置为false
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}"
答案 1 :(得分:2)
好吧,当您按下按钮时,MouseMove
和MouseEnter
都会被调用(即使使用空格键),这会导致Popup
在IsOpen
尝试关闭时{ {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
不应多次打开(包括按下按钮的时间)。