Invisible opened popup

此生再无相见时 提交于 2019-12-07 05:25:35

问题


Second day fighting this issue.

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>

and code

private void Button_MouseMove(object sender, MouseEventArgs e)
{
    popup.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?

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;

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");

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.

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.


回答1:


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 possible solutions I found, depending on your needs:

  1. Explicitly set IsOpen to false, after the popup closed (bash async)
  2. #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;
}

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



回答2:


Well, MouseMove and MouseEnter are both called when you press the button (even if with Spacebar key), so this leads to situation when Popup is trying to close while having IsOpen set to true at the same time. The simple solution could be to divide this two events.

One possible way can be to stick to MouseEnter and open Popup just once while hovering over given Button. Just as example:

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

While the same Button generates this events Popup should not be opened more than once (including the time when the button is pressed).



来源:https://stackoverflow.com/questions/24491382/invisible-opened-popup

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!