Chrisjan Lodewyks
Chrisjan Lodewyks

Reputation: 1337

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.

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?

Upvotes: 0

Views: 437

Answers (3)

Chrisjan Lodewyks
Chrisjan Lodewyks

Reputation: 1337

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!

Upvotes: 0

Hans Passant
Hans Passant

Reputation: 942408

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. Turn to the MSDN Library page for that function to see what is possible.

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. Respectively the bAlpha and crKey arguments in the api function. Alpha blending is what you are after here, it combines the pixels of the two buffers using a multiplier. The lower the alpha multiplier, the less a pixel contributes to the final pixel value sent to the monitor. 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 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.

Perhaps you can tell why you are having this problem now, the winapi restricts the effects to a window. With the additional requirement that it must be a top-level window, same thing as the WPF Window class. 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.

Note the comment in the linked article, Windows 8 supports specifying it for child windows too. That's almost surely done by DWM, the Desk Window Manager and enabled when Aero is enabled. Done in software instead of hardware, windows are rendered to memory and DWM composites them before sending the pixels to the video adapter. That capability is not yet exposed in .NET and will take time. Not very useful to WPF anyway since WPF doesn't use child windows like Winforms does.

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. 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.

Upvotes: 4

Arthur Nunes
Arthur Nunes

Reputation: 7058

Well, you can let your Window at normal opacity but change the transparency of the background (the alpha channel). 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. See this link.

Upvotes: 1

Related Questions