允许鼠标事件通过半透明Popup

时间:2014-07-04 08:43:48

标签: c# wpf xaml popup wpf-controls

我正在尝试从Popup内的控件执行拖放操作。被拖动的内容将被放置在拖放的位置,因此当拖动开始时,我想让Popup半透明以允许放置在它下面。但到目前为止,我没有让鼠标事件通过我的半透明Popup

以下xaml工作正常,当使用鼠标悬停Button时,Rectangle仍可点击

<Grid>
    <Rectangle Panel.ZIndex="2"
               Width="200"
               Height="200"
               Fill="Green"
               IsHitTestVisible="False"
               Opacity="0.5"/>
    <Button Content="Click Me"
            FontSize="22"
            FontWeight="Bold"/>
</Grid>

enter image description here

但是当鼠标悬停在Rectangle内的Popup时,以下xaml无法允许鼠标事件通过。

<Grid>
    <Popup Placement="Center"
           AllowsTransparency="True"
           IsHitTestVisible="False"
           IsOpen="True">
        <Rectangle Width="100"
                   Height="50"
                   Fill="Green"
                   IsHitTestVisible="False"
                   Opacity="0.5"/>
    </Popup>
    <Button Content="Click Me"
            FontSize="22"
            FontWeight="Bold"/>
</Grid>

enter image description here

我已尝试获取PopupRoot的{​​{1}}顶级父级,并为视觉树中的每个元素明确设置RectangleIsHitTestVisible,但它仍然没有不行。我可以通过将Opacity / Background设置为Fill的唯一方法是将Transparent / Transparent设置为Window,但它看起来很奇怪并且将非Popup的部分悬停仍然失败

我已阅读以下链接,但据我所知,这只适用于{{1}}而非{{1}}。 How to create a semi transparent window in WPF that allows mouse events to pass through

有没有人有任何解决方案或建议? : - )

2 个答案:

答案 0 :(得分:4)

感谢@NETscape发表的评论,我试图抓住Window的实际Popup。它适用于以下代码(最初显示Popup之后我可能会添加..)

// FromVisual can take any Visual inside the Popup..
HwndSource popupHwndSource = HwndSource.FromVisual(rectangle) as HwndSource;

将此与this question的答案相结合我创建了一个附加行为,该行为添加了可以在IsPopupEventTransparent中的任何子项上设置的属性Popup。起初,此解决方案导致了一个错误,该错误迫使用户在Window失去事件透明度后点击两次以重新激活Popup。我用&#34; Mouse.Capture - 解决方法&#34;。

解决了这个问题
elementInPopup.Dispatcher.BeginInvoke(new Action(() =>
{
    Keyboard.Focus(elementInPopup);
    Mouse.Capture(elementInPopup);
    elementInPopup.ReleaseMouseCapture();
}));

可以这样使用

<Popup AllowsTransparency="True"
       ...>
    <Border inf:PopupBehavior.IsPopupEventTransparent="{Binding SomeProperty}"
            BorderThickness="1"
            BorderBrush="Black"
            Background="White"
            Margin="0 0 8 8">
        <Border.Effect>
            <DropShadowEffect ShadowDepth="2.25" 
                              Color="Black"
                              Opacity="0.4"
                              Direction="315"
                              BlurRadius="4"/>
        </Border.Effect>
        <!--...-->
    </Border>
</Popup>

<强> PopupBehavior

public class PopupBehavior
{
    public static readonly DependencyProperty IsPopupEventTransparentProperty =
        DependencyProperty.RegisterAttached("IsPopupEventTransparent",
                                            typeof(bool),
                                            typeof(PopupBehavior),
                                            new UIPropertyMetadata(false, OnIsPopupEventTransparentPropertyChanged));

    public static bool GetIsPopupEventTransparent(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsPopupEventTransparentProperty);
    }
    public static void SetIsPopupEventTransparent(DependencyObject obj, bool value)
    {
        obj.SetValue(IsPopupEventTransparentProperty, value);
    }
    private static void OnIsPopupEventTransparentPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement element = target as FrameworkElement;
        if ((bool)e.NewValue == true)
        {
            FrameworkElement topParent = VisualTreeHelpers.GetTopParent(element) as FrameworkElement;
            topParent.Opacity = 0.4;
            HwndSource popupHwndSource = HwndSource.FromVisual(element) as HwndSource;
            WindowHelper.SetWindowExTransparent(popupHwndSource.Handle);
        }
        else
        {
            FrameworkElement topParent = VisualTreeHelpers.GetTopParent(element) as FrameworkElement;
            topParent.Opacity = 1.0;
            HwndSource popupHwndSource = HwndSource.FromVisual(element) as HwndSource;
            WindowHelper.UndoWindowExTransparent(popupHwndSource.Handle, element);
        }
    }
}

WindowHelper 根据此this question的回答

public static class WindowHelper
{
    private static Dictionary<IntPtr, int> _extendedStyleHwndDictionary = new Dictionary<IntPtr, int>();

    const int WS_EX_TRANSPARENT = 0x00000020;
    const int GWL_EXSTYLE = (-20);

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hwnd, int index);

    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

    public static void SetWindowExTransparent(IntPtr hwnd)
    {
        int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
        SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
        if (_extendedStyleHwndDictionary.Keys.Contains(hwnd) == false)
        {
            _extendedStyleHwndDictionary.Add(hwnd, extendedStyle);
        }
    }

    public static void UndoWindowExTransparent(IntPtr hwnd, FrameworkElement elementInPopup)
    {
        if (_extendedStyleHwndDictionary.Keys.Contains(hwnd) == true)
        {
            int extendedStyle = _extendedStyleHwndDictionary[hwnd];
            SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle);
            // Fix Focus problems that forces the users to click twice to
            // re-activate the window after the Popup loses event transparency
            elementInPopup.Dispatcher.BeginInvoke(new Action(() =>
            {
                Keyboard.Focus(elementInPopup);
                Mouse.Capture(elementInPopup);
                elementInPopup.ReleaseMouseCapture();
            }));
        }
    }
}

答案 1 :(得分:0)

问题不在于弹出窗口,但在应用于矩形时问题是颜色为Green,这会有效阻止鼠标事件通过

尝试使用透明背景的下面的示例,我放置了一个边框来显示存在

<Grid>
    <Popup Placement="Center"
           AllowsTransparency="True"
           IsHitTestVisible="False"
           IsOpen="True">
        <Border Width="100"
                Height="50"
                Background="Transparent"
                BorderBrush="Black"
                BorderThickness="4"
                IsHitTestVisible="False"
                Opacity="0.5" />
    </Popup>
    <Button Content="Click Me"
            FontSize="22"
            FontWeight="Bold" />
</Grid>

因此任何具有non zero alpha组件的颜色都会阻止鼠标事件

请参阅下面的alpha示例

  • #FF00FF00绿色Fail
  • #9900FF00半透明绿色Fail
  • #0100FF00几乎看不见绿色Fail
  • #0000FF00全透明绿色Pass

因此您需要具有透明色才能通过

传递鼠标事件

由于弹出窗口是在应用程序窗口顶部生成的分层窗口,因此如果您需要背景,则可能需要实现如何创建半透明窗口解决方案。在wpf中似乎没有构建解决方案