如何在WPF中创建一个半透明窗口,使鼠标事件能够穿过它?

41

我试图在WPF中创建类似Adobe Lightroom(http://www.youtube.com/watch?v=87hNd3vaENE)中的灯光关闭/变暗特效。

我的尝试是在现有窗口上创建另一个窗口,将其设置为透明,并在其上放置半透明的Path几何图形。但我希望鼠标事件能够穿透这个半透明的窗口(传递到下面的窗口)。

以下是简化版本:

<Window x:Class="LightsOut.MaskWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    AllowsTransparency="True" 
    WindowStyle="None"
    ShowInTaskbar="False"
    Topmost="True" 
    Background="Transparent">

<Grid>

    <Button HorizontalAlignment="Left" Height="20" Width="60">click</Button>

    <Path IsHitTestVisible="False" Stroke="Black" Fill="Black" Opacity="0.3">

        <Path.Data>
            <RectangleGeometry Rect="0,0,1000,1000 "/>
        </Path.Data>
    </Path>             

</Grid>

窗口完全透明,所以在路径未覆盖的地方,鼠标事件会直接穿过。到目前为止一切正常。路径对象上的IsHitTestvisible属性设置为false。因此,鼠标事件会穿过它,传递到同一表单上的其他控件(例如,您可以单击按钮,因为它在同一表单上)。

但鼠标事件不会穿过路径对象并传递到其下面的窗口。

有什么想法吗?或者更好的解决方法?

谢谢。

3个回答

69

我曾遇到类似的问题,并找到了解决方案:

public static class WindowsServices
{
  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)
  {
    var extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
    SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
  }
}

对于你的窗口集:

WindowStyle = None
Topmost = true
AllowsTransparency = true

在窗口的代码后台中添加:

protected override void OnSourceInitialized(EventArgs e)
{
  base.OnSourceInitialized(e);
  var hwnd = new WindowInteropHelper(this).Handle;
  WindowsServices.SetWindowExTransparent(hwnd);
}

然后,你就会看到——点击穿透窗口!请参见原答案:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a3cb7db6-5014-430f-a5c2-c9746b077d4f


这太棒了,我只想再完成一件事:隐藏光标。基本上是将光标设置为None,但是有了这个超酷的代码,光标会根据窗口下方的内容而改变。有没有办法让点击穿过我们的窗口并且不显示光标? - Peter Perháč
完美运作!我能够在 WinForms 应用程序中,使用你的“Click Through”方法,操作 WPF 窗口。 - Alex
2
不幸的是,这样做按钮现在看起来无法点击。 - David Khuu

2
你所描述的情况似乎是预期行为。一种解决方案是在路径上将填充设置为{x:Null},因为这是确保对象不进行命中测试的唯一可靠方式。

1
半透明度放在哪里了? - Martin Schneider

1
我有另一个想法。
如果你把鼠标光标正下方的一个像素完全透明,会怎样?:]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接