質問

According to a lot of questions here on SO, the best way to make the background of a form transparent is to set it to a fairly unused color (like Magenta) then set the form's TransparencyKey to that color.

this.BackColor = Color.Magenta;
this.TransparencyKey = Color.Magenta;

That part works fine. The problem that I'm running into is that it works fine except behind a MenuStrip. A semi-transparent background in the MenuStrip + transparent background in the form ends up like this:

That's what the MenuStrip looks like. The part where it turns magenta is when the MenuStrip itself is set to be semi-transparent.

This is what my form initialization function looks like:

public frmMain() {
    this.TransparencyKey = Color.Magenta;
    InitializeComponent();
    this.BackColor = Color.Magenta;

    if(Properties.Settings.Default.windowTheme == 0) { // theme is light
        menuStrip.Renderer = new ToolStripProfessionalRenderer(new LightTheme());
    }
    else if(Properties.Settings.Default.windowTheme == 1) {
        menuStrip.Renderer = new ToolStripProfessionalRenderer(new DarkTheme());
    }

    menuStrip.Invalidate();
}

And my custom renderer for the MenuStrip (colors are just for testing right now):

public class LightTheme: ProfessionalColorTable {
    public override Color MenuItemSelected {
        get { return Color.FromArgb(255, Color.Yellow); }
    }

    public override Color MenuStripGradientBegin {
        get { return Color.FromArgb(255, Color.Black); }
    }

    public override Color MenuStripGradientEnd {
        get { return Color.FromArgb(0, Color.Gainsboro); }
    }
}

What I'm really trying to accomplish here is having the form transparent and part of the MenuStrip transparent so you can see the desktop underneath it. Is there a better way to do it, or a way to fix this?

役に立ちましたか?

解決

public override Color MenuStripGradientEnd {
    get { return Color.FromArgb(0, Color.Gainsboro); }
}

This is where the problem started, you specified an alpha of 0 for the gradient end color. Which works nicely, the alpha is blended well. But it is applied to the background color. So you see a blend of magenta. Which no longer matches the color key so the pixels become visible.

The layered windows feature built into Windows support two ways to blend a window against the desktop, the underlying winapi call is SetLayeredWindowAttributes(). Winforms supports the LWA_COLORKEY option, enabled by setting the TransparencyKey property, but not the LWA_ALPHA option. Called "per-pixel alpha". You'll find plenty of google hints on the pinvoke you'd need to enable it.

But you'll then be in for a rude surprise, you'll see that most of the controls in the toolbox stop working. Text rendering in Winforms is done by GDI, an api that renders text with an alpha of 0. With the inevitable side-effect that, when you turn on per-pixel alpha, that text is now transparent as well. Which you could call a feature but drastically impractical since you don't control the desktop color nor what windows are behind yours.

That's fixable as well by replacing controls and use a text rendering api like DirectWrite. But that's rather a lot of work and you just don't get much benefit from Winforms anymore. WPF supports per-pixel alpha, it doesn't use the standard Windows controls.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top