C# 使用alpha覆盖组件,当其下的控件重绘时重绘

C# 使用alpha覆盖组件,当其下的控件重绘时重绘,c#,.net,winforms,alpha,C#,.net,Winforms,Alpha,我创建了一个自定义控件,我想用它在表单的一部分上按需覆盖状态信息。根据信息的类型,它应该显示文本并具有背景色。这是仍然不完整的代码 public partial class StatusPanel : UserControl { public enum PanelStyle { Info, Warning, Error } public PanelStyle Style { get; set; } pub

我创建了一个自定义控件,我想用它在表单的一部分上按需覆盖状态信息。根据信息的类型,它应该显示文本并具有背景色。这是仍然不完整的代码

public partial class StatusPanel : UserControl
{
    public enum PanelStyle
    {
        Info,
        Warning,
        Error
    }

    public PanelStyle Style { get; set; }

    public StatusPanel()
    {
        InitializeComponent();

        this.imgGreen = new Bitmap(256, 256, PixelFormat.Format32bppArgb);
        using(Graphics g = Graphics.FromImage(this.imgGreen))
        {
            g.Clear(Color.Transparent);
            Brush bg = new SolidBrush(Color.FromArgb(200, Color.Green));
            g.FillRectangle(bg, 0, 0, 256, 256);
        }

        this.imgYellow = new Bitmap(256, 256, PixelFormat.Format32bppArgb);
        using(Graphics g = Graphics.FromImage(this.imgYellow))
        {
            g.Clear(Color.Transparent);
            Brush bg = new SolidBrush(Color.FromArgb(10, Color.Yellow));
            g.FillRectangle(bg, 0, 0, 256, 256);
        }
    }

    protected readonly Font font = new Font("Arial", 12.0F);

    protected readonly Brush textBrush = new SolidBrush(Color.Black);

    protected readonly Image imgGreen;

    protected readonly Image imgYellow;

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

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        // do not draw background
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
        e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
        e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

        Image img = GetImage();

        e.Graphics.DrawImage(img, 0, 0, this.Width, this.Height);

        e.Graphics.DrawString("ABC", this.font, this.textBrush, 1.0F, 1.0F);
    }

    protected Image GetImage()
    {
        return (this.Style == PanelStyle.Info) ? this.imgGreen : this.imgYellow;
    }
}
这个很好用。但是,当我在窗体上放置一些按钮,并且其中一个控件位于这些按钮前面时,当鼠标移动到按钮上时,这些按钮将“过度绘制”,高亮效果将重新绘制它们


如何通知我的组件它需要重新绘制,因为基础控件已重新绘制?

Parent.control
下的所有控件注册绘制处理程序,并为注册绘制处理程序的
Parent.ControlAdded
注册处理程序

大概是这样的:

private void myDummyUserControl_Load(object sender, EventArgs e)
{
    var uc = (DummyUserControl)sender;
    uc.Parent.ControlAdded += new ControlEventHandler(Parent_ControlAdded);
    foreach (Control c in uc.Parent.Controls)
    {
        if (uc == c)
            continue;
        c.Paint += new PaintEventHandler(c_Paint);
    }
}

void c_Paint(object sender, PaintEventArgs e)
{
    //checks & paint stuff here
}

void Parent_ControlAdded(object sender, ControlEventArgs e)
{
    e.Control.Paint += new PaintEventHandler(c_Paint);
}
//编辑


不确定是否需要使用递归来遍历子控件树,是否也需要在这些子控件上添加处理程序

Parent.Control
下的所有控件注册一个绘制处理程序,并为注册绘制处理程序的
Parent.ControlAdded
注册一个处理程序

大概是这样的:

private void myDummyUserControl_Load(object sender, EventArgs e)
{
    var uc = (DummyUserControl)sender;
    uc.Parent.ControlAdded += new ControlEventHandler(Parent_ControlAdded);
    foreach (Control c in uc.Parent.Controls)
    {
        if (uc == c)
            continue;
        c.Paint += new PaintEventHandler(c_Paint);
    }
}

void c_Paint(object sender, PaintEventArgs e)
{
    //checks & paint stuff here
}

void Parent_ControlAdded(object sender, ControlEventArgs e)
{
    e.Control.Paint += new PaintEventHandler(c_Paint);
}
//编辑


不确定是否需要使用递归来遍历子控件树,是否也需要在这些子控件上添加处理程序

你的意思是说,当所有其他组件被绘制时,告诉我的状态面板重新绘制?可能需要手动检查组件边界是否重叠?基本上是的。当然,您可以通过注册EventHandler进行重新定位或调整大小,并基于重叠检查注册或取消注册绘制处理程序,使这一点变得更复杂boundaries@DarkSquirrel42好的,当我在其他控件的绘制事件中使我的控件无效时,如果它们相交,这会有所帮助。还有一点闪烁效应。有没有办法在这种情况下使用双缓冲?@Zool抱歉,我从未在.net环境中使用过双缓冲,但为了减少不必要的影响,您可以尝试只重新绘制需要重新绘制的区域。。。请参见PaintEventArgs和GraphicsProperties@DarkSquirrel42问题是我既不知道绘制其他控件的逻辑,也不想。想象一个普通的Winforms.按钮在我的控制下。在它的绘制事件中,我现在检查它是否在我的控制下,如果在我的控制下,我的控件将失效以重新绘制。但我无法阻止按钮自行绘制。事实上,这是必要的,因为我需要一个完整的按钮来正确绘制alpha控件。因此,目前我还不知道如何最大限度地减少这种影响。目前的解决方案可能已经足够好了。否则,我将在将来添加一个新问题。到目前为止非常感谢。那么你的意思是说,当所有其他组件上漆时,告诉我的状态面板重新上漆?可能需要手动检查组件边界是否重叠?基本上是的。当然,您可以通过注册EventHandler进行重新定位或调整大小,并基于重叠检查注册或取消注册绘制处理程序,使这一点变得更复杂boundaries@DarkSquirrel42好的,当我在其他控件的绘制事件中使我的控件无效时,如果它们相交,这会有所帮助。还有一点闪烁效应。有没有办法在这种情况下使用双缓冲?@Zool抱歉,我从未在.net环境中使用过双缓冲,但为了减少不必要的影响,您可以尝试只重新绘制需要重新绘制的区域。。。请参见PaintEventArgs和GraphicsProperties@DarkSquirrel42问题是我既不知道绘制其他控件的逻辑,也不想。想象一个普通的Winforms.按钮在我的控制下。在它的绘制事件中,我现在检查它是否在我的控制下,如果在我的控制下,我的控件将失效以重新绘制。但我无法阻止按钮自行绘制。事实上,这是必要的,因为我需要一个完整的按钮来正确绘制alpha控件。因此,目前我还不知道如何最大限度地减少这种影响。目前的解决方案可能已经足够好了。否则,我将在将来添加一个新问题。谢谢你。