C# 控件分层时如何在Windows窗体中创建透明控件

C# 控件分层时如何在Windows窗体中创建透明控件,c#,.net,winforms,C#,.net,Winforms,我试图实现一个“可填充表单”,其中可编辑文本字段显示在点阵打印机预打印表单的图像上方。(使用c#和Windows窗体并以.Net 2.0为目标)我的第一个想法是使用图像作为Windows窗体的背景,但在滚动时它看起来很可怕,而且不能正确滚动内容 我的下一个尝试是创建一个固定大小的窗口,其中的面板溢出了窗口的边界(用于滚动)。我在面板中添加了一个PictureBox,并在其顶部添加了我的文本框。这很好,只是文本框不支持透明,所以我尝试了几种方法使文本框透明。一种方法是使用奇怪的背景色和透明度键。另

我试图实现一个“可填充表单”,其中可编辑文本字段显示在点阵打印机预打印表单的图像上方。(使用c#和Windows窗体并以.Net 2.0为目标)我的第一个想法是使用图像作为Windows窗体的背景,但在滚动时它看起来很可怕,而且不能正确滚动内容

我的下一个尝试是创建一个固定大小的窗口,其中的面板溢出了窗口的边界(用于滚动)。我在面板中添加了一个PictureBox,并在其顶部添加了我的文本框。这很好,只是文本框不支持透明,所以我尝试了几种方法使文本框透明。一种方法是使用奇怪的背景色和透明度键。另一个在以下链接中描述的是创建一个允许透明性的派生类:

这两种方法都不起作用,因为我已经发现,Windows窗体中的“透明度”仅仅意味着窗口的背景被绘制到控件背景上。由于PictureBox位于窗口背景和文本框之间,因此它使文本框看起来不是透明的,只是具有与窗口背景色相同的背景色。使用透明键方法,整个应用程序变得透明,以便您可以在后台看到VisualStudio,这不是我想要的。因此,现在我尝试实现一个从TextBox派生的类,该类重写OnPaint或OnPaintBackground,将PictureBox图像的适当部分绘制到控件背景上,以产生如下链接中所述的透明效果:

首先,我无法让它工作(我尝试了各种方法,要么得到一个完全黑色的控件,要么只是一个标准的标签背景),其次,我从DrawToBitmap方法中得到了一些异常,这些异常包含神秘的消息“附加信息:targetBounds”。根据MSDN的以下链接,我相信这是因为位图太大了——不管是哪种情况,在这里捕获整个表单图像似乎效率低下,因为我真的只想要一小块

这是我的最新尝试。有人能帮我实现OnPaintBackground吗,或者建议一种不同的方法?提前谢谢

public partial class TransparentTextbox : TextBox
{
    public TransparentTextbox()
    {
        InitializeComponent();
        SetStyle(ControlStyles.OptimizedDoubleBuffer |
                    ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.ResizeRedraw |
                    ControlStyles.UserPaint, true);
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        //base.OnPaintBackground(e); // not sure whether I need this
        if (Parent != null)
        {
            foreach (Control c in Parent.Controls)
            {
                if (c.GetType() == typeof(PictureBox))
                {
                    PictureBox formImg = (PictureBox)c;
                    Bitmap bitmap = new Bitmap(formImg.Width, formImg.Height);
                    formImg.DrawToBitmap(bitmap, formImg.Bounds);
                    e.Graphics.DrawImage(bitmap, -Left, -Top);

                    break;
                }
            }

            Debug.WriteLine(Name + " didn't find the PictureBox.");
        }
    }
}

注意:这已经被标记为重复,但我在我的原始帖子中引用了“重复问题”,并解释了为什么它不起作用。该解决方案仅在文本框直接位于窗口上方时有效-如果另一个控件(如my Panel和PictureBox)位于窗口和文本框之间,则.Net会将窗口背景绘制到文本框背景上,从而使其背景看起来呈灰色,不透明。

我想我终于弄清了这件事的真相。我在类中添加了一个位图变量,当我实例化文本框时,我将其设置为只包含位于控件后面的表单图像部分。然后我重载OnPaintBackground以显示位图,重载OnPaint以手动绘制文本字符串。以下是我的TransparentTextbox类的更新版本:

public partial class TransparentTextbox : TextBox
{
    public Bitmap BgBitmap { get; set; }

    public TransparentTextbox()
    {
        InitializeComponent();
        SetStyle(ControlStyles.OptimizedDoubleBuffer |
                    ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.ResizeRedraw |
                    ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.DrawString(this.Text, this.Font, Brushes.Black, new PointF(0.0F, 0.0F));
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        e.Graphics.DrawImage(BgBitmap, 0, 0);
    }
}
。。。下面是我如何实例化的相关部分:

Bitmap bgImage = (Bitmap)Bitmap.FromStream(Document.FormImage);

PictureBox pb = new PictureBox();
pb.Image = bgImage;
pb.Size = pb.Image.Size;
pb.Top = 0;
pb.Left = 0;
panel1.Controls.Add(pb);

foreach (FormField field in Document.FormFields)
{
    TransparentTextbox tb = new TransparentTextbox();   
    tb.Width = (int)Math.Ceiling(field.MaxLineWidth * 96.0);
    tb.Height = 22;
    tb.Font = new Font("Courier", 12);
    tb.BorderStyle = BorderStyle.None;
    tb.Text = "Super Neat!";
    tb.TextChanged += tb_TextChanged;
    tb.Left = (int)Math.Ceiling(field.XValue * 96.0);
    tb.Top = (int)Math.Ceiling(field.YValue * 96.0);
    tb.Visible = true;

    Bitmap b = new Bitmap(tb.Width, tb.Height);
    using (Graphics g = Graphics.FromImage(b))
    {
        g.DrawImage(bgImage, new Rectangle(0, 0, b.Width, b.Height), tb.Bounds, GraphicsUnit.Pixel);
        tb.BgBitmap = b;
    }
    panel1.Controls.Add(tb);
}

我仍然需要研究文本在突出显示时的外观,以及其他类似的事情,但我觉得我走在了正确的轨道上+1感谢Reza Aghaei和Mangist对其他可行解决方案的评论

我认为这在Windows窗体标准文本框中是不可能的。如果您愿意使用第三方工具包(我可以推荐),Infragistics可以使用背景图像和来源为您的问题提供解决方案。看看这篇文章:或者这篇:这是Windows窗体中的一个限制,一些第三方组件几乎可以修复。但它将为一个简单的Winforms项目增加大量的权重和引用。切换到WPF是不可能的吗?像这样的东西很容易适应。@Reza-这看起来很有希望-示例应用程序基本上正在做我想做的事情。只需包含源代码并将我的TransparentTextbox更改为他的一个控件,就可以得到与我自己的类类似的结果,但我会更深入一点——如果他的作品成功的话,我肯定会遗漏一些东西。@KevinBBurns——我正在尝试制作一个类库,可以在较新的WPF应用程序和较旧的WinForms应用程序之间共享。。。我很确定我可以让WPF解决方案正常工作,但无论如何,我需要使用它的主要地方是在现有的WinForms应用程序中。