4

I have run into a very strange issue today:

I have a popup menu that opens when I hover above an image. The popup menu is positioned right of the image.

this popup menu is templated to look like a rectangle with a little arrow pointing to the image

the menu contains clickable elements, so I need to be able to move the mouse from the image to the menu without it closing in between, and this is where I get confused: if I move the mouse right over the tip of the arrow and then the menu, everything works fine. If I move the mouse over the transparent space between the image and the menu (above or under the arrow), the menu disappears.

Here is the template for the menu:

<Popup AllowsTransparency="True" Name="c_popup" Width="300" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right">
    <Grid Background="Transparent">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10"  />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Path Data="M 0 10 L 10 0 10 20 Z" Stroke="#252C37" Fill="#252C37" Margin="0,18,0,0" Grid.Column="0" />

        <Grid Grid.Column="1" Background="#252C37">

            <TextBlock Text="{Binding Name}" Margin="20,10,0,0" FontSize="18" Foreground="White" HorizontalAlignment="Stretch" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" />

        </Grid>
    </Grid>
</Popup>

you'll notice that I specifically put Background="Transparent" and not Null (I am aware of the effect this as on the hitTesting, see this question)

funny thing is, though: If I put Background="#01000000", it works as expected. (And I get almost what I want, since this is almost a transparent background)

but I would still like to know what is going on there...

I suspect it has something to do with the fact that this is a popupmenu. I assume WPF does something to remove the hitTesting on any surface that is transparent in a popup menu, either when the background is null (which is expected) or even if it is specifically set to transparent (not expected). Can anyone confirm this?

Community
  • 1
  • 1
David
  • 6,014
  • 4
  • 39
  • 55
  • Think it's more "Windows" than WPF doing this. `Windows supports transparency at the HWND level through a feature called "layered windows"` [Detailed explanation](http://social.msdn.microsoft.com/Forums/vstudio/en-US/ae8a8a21-9c68-4987-8480-a2f03a161784/mouse-over-transparent-control-doesnt-generate-events). Would guess you'd need to specify the Background like you guessed or use an opacity of something like 0.01 on another background element to make the system force it to accept mouseover events. – Viv Jul 03 '13 at 09:33
  • Now in this case even if you do not actually have `AllowTransparency="True"` like the OP in the link I posted, A `Popup` control internally ends up as a new Chrome-less Window anyways which Snoop can confirm(Totally different visual tree's). So the answer in that question should apply. – Viv Jul 03 '13 at 09:47
  • I do have the allowTransparency=true, But event for a chromeLess window, I would have thought that setting explicitly the Background="Transparent" would have allowed me to hit on a mouseEvent like with any other wpf control. I'll have a look at your link – David Jul 03 '13 at 09:52
  • ok, as good an explanation as I can find. You should put your comment as answer so I can accept it – David Jul 03 '13 at 10:01
  • Done. Yeh as stated in the MSDN question, if this control was say a `Button`, even with `AllowTransparency="True"` it would have got mouse-over events since it's parent Window did not have AllowTransparency set. In your case it's just a combination of that issue occurring on a Popup which itself creates a new chrome-less Window. – Viv Jul 03 '13 at 10:13

1 Answers1

6

Converting my comment to an answer.

This seems to be more of a "Windows OS" issue than WPF specifically in the way AllowTransparency="True" at a Window level makes the system ignore the element for mouseover events when Background="Transparent" or Opacity="0" on the element..

A detailed explanation of this behavior can be found Here

Adding the MSDN answer just in case the link goes missing later:

Windows supports transparency at the HWND level through a feature called "layered windows".
Layered windows are represented by a bitmap. The Operation System(OS) renders the bitmap whenever it needs to.
For the OS need to respond very quickly to mouse movement, Windows uses a dedicated Raw Input Thread (RIT). RIT runs in the kernel and handles the singals from mouse hardware. RIT can scan over the HWND hierarchy to detect which window the mouse is over. For normal windows, the RIT checks the mouse position against the window's rectangle. For layered windows, the RIT looks in the bitmap that specifies the content for the window and checks the effective transparency at that location. The effective transparency can be affected by opacity, color and alpha channel. If the pixel is 100% transparent, the RIT skips the window and keeps looking. This point is the reason that MouseMove event is not fired. If the Background of window and control are both Transparent, all the pixels that represent this control(Canvas in your example) in the layered windows are totally transparent. As described above, RIT will skip them and never send WM_MOUSEMOVE message. So if you want only show up the control only when the mouse is over and otherwise and the window is transparent, you have to make the control not 100% transparent.

Something to note in this case is, even though Popup is within a Window that does not have AllowTransparency="True", Popup generates a Chrome-less window itself and the AllowTransparency="True" on the Popup affect this new chromeless-Window the same way as mentioned in the MSDN link above.

If this control were just a standard control like Button/Rectangle... then just setting the Background="Transparent" would make it work fine and not have this issue.

Viv
  • 17,170
  • 4
  • 51
  • 71