简体   繁体   English

更改窗口不透明度,使子级保持不变

[英]Change window opacity leaving Children the same

I'm having an issue with the opacity of a window in WPF, what I would like to do is change the opacity of the window but leave the childrens opacity the same. 我在WPF中窗口的不透明度遇到问题,我想做的是更改窗口的不透明度,但让孩子的不透明度保持不变。

Here is my current code: 这是我当前的代码:

      Window window = new Window();
  window.WindowStyle = WindowStyle.None;
  window.AllowsTransparency = true;
  window.Background = Brushes.Black;
  window.Opacity = 0.5;
  window.ShowInTaskbar = false;

  double taskBarHeight = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height - System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
  window.Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height - taskBarHeight;
  window.Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
  window.Top = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Top;
  window.Left = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Left;

  LoginCtl ctl = new LoginCtl(this);

  window.Content = ctl;
  window.ShowDialog();

I understand that children cannot have a higher opacity than their parents, but is there a possible workaround for this? 我知道孩子的混浊度不能比父母高,但是有没有可能的解决方法?

Maybe it helps to understand how window opacity works. 也许有助于了解窗口不透明度的工作原理。 It is implemented in hardware, a feature of the video adapter called "overlays". 它是通过硬件实现的,视频适配器的一项功能称为“覆盖”。 It is exposed in the winapi through the WS_EX_LAYERED window style flag and the SetLayeredWindowAttributes() api function . 它通过WS_EX_LAYERED窗口样式标志和SetLayeredWindowAttributes()api函数在winapi中公开。 Turn to the MSDN Library page for that function to see what is possible. 转到该功能的MSDN库页面,以查看可能的结果。

The video adapter has a mixer that can combine the pixels of two video memory buffers. 视频适配器具有一个混频器,可以将两个视频内存缓冲区的像素合并在一起。 That mixer supports two effects, alpha blending and color keying. 该混音器支持两种效果,即alpha混合和颜色键控。 Respectively the bAlpha and crKey arguments in the api function. api函数中的bAlpha和crKey参数分别。 Alpha blending is what you are after here, it combines the pixels of the two buffers using a multiplier. Alpha混合就是您所需要的,它使用乘法器将两个缓冲区的像素合并在一起。 The lower the alpha multiplier, the less a pixel contributes to the final pixel value sent to the monitor. alpha乘数越低,像素对发送到监视器的最终像素值的贡献就越小。 Color keying is a common trick in video processing, weather forecaster in front of a weather map, when a pixel matches the color key then it is replaced by the pixel from the other buffer. 颜色键控是视频处理中的常见技巧,天气预报员位于天气图的前面,当一个像素与颜色键匹配时,它将被另一个缓冲区中的像素替换。 Color keying isn't directly exposed in WPF but it is in Winforms with the Form.TransparencyKey property. 颜色键控不是直接在WPF中公开的,而是在Winforms中具有Form.TransparencyKey属性的。 WPF uses per-pixel alpha, it draws with 32bpp pixels that includes the alpha component, unlike the olden native Windows components that Winforms uses which draw with 24bpp GDI calls. WPF使用每像素Alpha,它以32bpp像素进行绘制,其中包括Alpha组件,这与Winforms使用较旧的本机Windows组件(以24bpp GDI调用进行绘制)不同。

Perhaps you can tell why you are having this problem now, the winapi restricts the effects to a window. 也许您可以说出为什么现在遇到此问题,winapi将效果限制在一个窗口内。 With the additional requirement that it must be a top-level window, same thing as the WPF Window class. 附加要求它必须是顶级窗口,与WPF Window类相同。 The alpha blend effect is therefore applied to all the pixels in the window, you cannot selectively turn it off for parts of the window that are used to render a control. 因此,alpha混合效果将应用于窗口中的所有像素,您无法为用于渲染控件的窗口部分选择性地将其关闭。

Note the comment in the linked article, Windows 8 supports specifying it for child windows too. 请注意链接文章中的注释,Windows 8也支持为子窗口指定注释。 That's almost surely done by DWM, the Desk Window Manager and enabled when Aero is enabled. 这几乎肯定由DWM,Desk Window Manager(桌面窗口管理器)完成,并在启用Aero时启用。 Done in software instead of hardware, windows are rendered to memory and DWM composites them before sending the pixels to the video adapter. 用软件而不是硬件来完成,将窗口渲染到内存中,并在将像素发送到视频适配器之前将DWM进行合成。 That capability is not yet exposed in .NET and will take time. 该功能尚未在.NET中公开,将需要一些时间。 Not very useful to WPF anyway since WPF doesn't use child windows like Winforms does. 无论如何,对WPF来说不是很有用,因为WPF不像Winforms那样使用子窗口。

Enough introduction to understand what you need to do to solve this problem. 足够的介绍,以了解解决此问题所需的操作。 You'll need to do your own layering. 您需要做自己的分层。 You need two windows, one sandwhiched on top of the other. 您需要两个窗口,一个在另一个之上。 The bottom one should be just a plain Window with only the Opacity set. 底部应该只是一个仅设置了“不透明度”的普通窗口。 It provides the background. 它提供了背景。 Then you need another Window that contains the controls, with its WindowStyle set to None and Background set to transparent so you can see the background pixels rendered by the bottom window. 然后,您需要另一个包含控件的窗口,其WindowStyle设置为None,而Background设置为transparent,以便您可以看到底部窗口渲染的背景像素。 Its Owner should be set to the bottom window so it is always on top and you need to move and resize it when the bottom window is moved or resized by the user. 它的所有者应设置为底部窗口,以便它始终位于顶部,并且当用户移动底部窗口或调整底部窗口的大小时,您需要移动它并调整其大小。

Well, you can let your Window at normal opacity but change the transparency of the background (the alpha channel). 好了,您可以让Window处于正常的不透明度,但可以更改背景(Alpha通道)的透明度。 If that is not enough and you want change the opacity of elements of the chrome as well, you can try to modify it yourself. 如果这还不够,并且您还想更改chrome元素的不透明度,则可以尝试自己进行修改。 See this link . 看到这个链接

The solution that I used can be found here . 我使用的解决方案可以在这里找到。

What I did was to create a window with only a grid and a rectangle: 我要做的是创建一个只有网格和矩形的窗口:

    <Grid Name="MainGrid">
    <Rectangle Fill="Gray" Opacity="0.7" />
    </Grid>

And then from code behind do the following: 然后从代码后面执行以下操作:

  LoginWindow win = new LoginWindow();
  win.ShowInTaskbar = false;

  LoginCtl ctl = new LoginCtl(this);
  win.MainGrid.Children.Add(ctl);
  win.ShowDialog();

This way the background of the window is see trough but the controls added to it are opaque. 这样,窗口的背景可以看到低谷,但是添加到它的控件是不透明的。

Hope this helps someone! 希望这对某人有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM