C# 创建半透明面板/控件。有没有万无一失的办法?

C# 创建半透明面板/控件。有没有万无一失的办法?,c#,.net,custom-controls,C#,.net,Custom Controls,我正在尝试创建一个半透明控件,该控件派生自System.Windows.Forms.Panel。[编辑:基本上我想要实现的是]: 我浏览了大量的网络文章和问题,并得出以下结论: class SeeThroughPanel : Panel { public SeeThroughPanel() { } protected override CreateParams CreateParams { get { var cp =

我正在尝试创建一个半透明控件,该控件派生自
System.Windows.Forms.Panel
。[编辑:基本上我想要实现的是]:

我浏览了大量的网络文章和问题,并得出以下结论:

class SeeThroughPanel : Panel
{
    public SeeThroughPanel()
    {
    }

    protected override CreateParams CreateParams {
        get {
            var cp = base.CreateParams;
            cp.ExStyle |= 0x00000020;
            return cp;
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        //base.OnPaint(e);
        e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(50, 0, 0, 0)), this.ClientRectangle);
    }
}
其结果是(请注意,此代码也不会使其成为真正的半透明。按钮以全色显示,与上图不同):

但是,一旦我做了一些导致在半透明面板边界内重新绘制任何其他控件的操作,它就会被透支(在本例中,我滚动了底层控件):


所以我的问题是,我怎样才能避免这种情况?一定有办法。毕竟,web浏览器一直在处理这种渲染。

Windows窗体控件的透明功能还有很多需要改进的地方,这是一个明显的捏造。控件不是真正透明的,它只是通过查看其父控件的背景并在OnPaintBackground方法期间将图像或背景的适当部分复制到自己的曲面上来假装透明

protected override void OnPaintBackground(PaintEventArgs pevent)
{
  //do not allow the background to be painted 
}
这意味着,放置在同一父控件上的另一个控件之上的“透明”控件实际上会掩盖其他子控件。图1显示了这种作用

窗体右侧的面板控件会遮挡PictureBox控件,并仅显示父控件的背景

为了使控件真正透明,我们需要做几件事。首先,有必要更改窗口的行为,为其提供WS_EX_透明样式。这是通过重写CreateParams属性来实现的,以便在实例化控件时包含正确的窗口样式。下面的列表显示了此属性覆盖

protected override CreateParams CreateParams
{
  get
  {
    CreateParams cp=base.CreateParams;
    cp.ExStyle|=0x00000020; //WS_EX_TRANSPARENT
    return cp;
  }
}
当我们需要更新图形时,我们需要做的第二件事是使控件的父控件无效,而不是控件本身。这确保了在我们需要进行自己的图形输出之前,控件后面的任何内容都会被绘制。为此,需要一个如下清单所示的例程

protected void InvalidateEx()
{
  if(Parent==null)
    return;
  Rectangle rc=new Rectangle(this.Location,this.Size);
  Parent.Invalidate(rc,true);
}
最后,我们需要确保背景绘制例程不会因为去掉OnPaintBackground方法而弄乱最近重新绘制的父表单内容

protected override void OnPaintBackground(PaintEventArgs pevent)
{
  //do not allow the background to be painted 
}
现在控件已准备好进行其余修改。此时必须注意,透明控件不适合使用标准SetStyle方法进行双缓冲。提供给代码的内存位图具有不透明背景,不允许仔细保留的父像素显示出来

为了完成本文,下面的列表中显示了一个简单的控件,该控件只在其表面绘制移动的椭圆

using System;
using System.Drawing;
using System.Windows.Forms;

internal class SeeThroughPanel : Panel
{

    public SeeThroughPanel()
    {
    }

    protected void TickHandler(object sender, EventArgs e)
    {
        this.InvalidateEx();
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;

            cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT

            return cp;
        }
    }

    protected void InvalidateEx()
    {
        if (Parent == null)
        {
            return;
        }

        Rectangle rc = new Rectangle(this.Location, this.Size);

        Parent.Invalidate(rc, true);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {

    }

    private Random r = new Random();

    protected override void OnPaint(PaintEventArgs e)
    {
        
        e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(128, 0, 0, 0)), this.ClientRectangle);
    }
}

我现在已经做了一些测试

你把几个问题混为一谈,让我们把它们分开:

  • 没有WebBrowser是使用Winforms用C语言编写的。所以这不是为什么这必须是可能的

  • 您的按钮几乎肯定不在表单的控件集合中。您需要将其编写为脚本,或者使用一些UI技巧(*)将其放置在另一个控件上,而不将其添加到控件中

  • 当您滚动时,您将看到滚动控件报告中的任何内容作为其表面

以下是两个屏幕截图:

这是在启动之后:

…这是在我向右滚动一点之后:

我已使用此代码确保Z顺序正确:

button1.Parent = this;
panel1.BringToFront();
button1.BringToFront();
seeThroughPanel1.BringToFront();
注意如何节省按钮的空间;这显示了如何使用旧曲面

要解决这个问题,您必须先找到当前的表单surfacese(可能是通过Control.DrawToBitmap),然后使用它的正确部分来绘制“半透明”面板。当然,它必须在捕获窗体的当前曲面之前隐藏

在我所有糟糕的想法中,这似乎是最糟糕的想法之一


*诀窍是用键盘将其移动到容器上,而不是用鼠标;使用此技巧,它只需移动而不改变其父容器。对于将控件放置在选项卡控件的选项卡顶部也很有用。。。但是我太懒了,所以我把它编码了。

谢谢。但不幸的是,这不是我的要求。我把问题弄得不清楚是我的错。(我随后更新了问题)。我想要的是一个具有半透明背景的控件。但这篇文章描述了一个透明的控件。这对我来说很有效,只是做了一些小的调整,特别是取消了OnPaintBackground。谢谢分享。VS Community 2013/WinformsIt看起来好像按钮在面板上,并且已经被滚动掉了,不是吗?您是否检查了
按钮。Parent
?这不会解决您的问题,但我建议切换到WPF:该框架比Winforms功能强大得多。有了WPF,你想做的事情将变得微不足道。重复一下你在所有帖子中读到的内容:控件本身从来都不是真正透明的,它们只是通过让原始父级的外观发光来伪装它,这就限制了家长可以看到的控件。@MarioVernari:无法切换到WPF,因为我使用的是一个基于winforms的框架。@TaW:问题不在于按钮。问题是,它前面的半透明面板被画得太长了。+1用于编写代码和自己进行测试。谢谢<代码>没有WebBrowser是使用Winforms用C语言编写的。如果需要,我非常乐意探索Win32 API
您的按钮几乎肯定不在表单的控件集合中
正确。它是通过代码添加的。但是用大尺寸的嵌套面板重复实验再现了这种行为。我不是在要求另一个答案。有了你的答案和我读到的许多其他答案,我将