在 .NET Compact Framework 中创建透明控件






4.32/5 (10投票s)
本文介绍了如何在 .NET Compact Framework 中创建透明控件

引言
.NET Compact Framework 不提供具有透明背景的现成控件。本文介绍了如何创建用户控件来克服这个问题。
背景
在我最近正在开发的 .NET Compact Framework 应用程序中,我需要在窗体的背景中添加图像。我使用了这个视频教程中的代码。但是,该视频还告诉我们,.NET Compact Framework 中的标签控件(和其他控件)不支持透明背景。您必须创建自己的用户控件。我找到了 Per Ola Sæther 的一篇很好的文章在 .NET Compact Framework 中创建具有透明标签的渐变背景。它帮助我创建了我的解决方案。
Using the Code
创建透明控件的基本思想是覆盖控件的 OnPaintBackgound
方法,使其调用父窗体的 OnPaintBackgound
来绘制背景,然后在上面绘制控件的内容。
在那篇文章中,作者展示了如何创建一个透明标签控件。但是代码可以简化。我还做了一些重构工作,因此它可以扩展到不仅仅是标签控件。
首先,我创建了那篇文章中介绍的相同接口。
public interface IPaintControl
{
// have the background painted
void InvokePaintBackground(PaintEventArgs e);
}
然后我创建了一个基窗体,这样我就不必为每个窗体编写相同的代码。
public class CcForm : Form, IPaintControl
{
public virtual void InvokePaintBackground(PaintEventArgs e)
{
OnPaintBackground(e);
}
}
创建了一个基本控件,以便我们不仅可以拥有透明标签,还可以拥有其他类型的控件,例如单选按钮和复选框。它有一个名为 TransparentBackground
的属性。如果您出于某种原因不希望控件是透明的,您可以更改此属性。在 OnPaintBackground
方法中,它调用其父级的 InvokePaintBackground
来绘制背景。
public class CcTransparentControl : Control
{
private bool _transparentBackgound = true;
public bool TransparentBackground
{
get
{
return _transparentBackgound;
}
set
{
_transparentBackgound = value;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
if (_transparentBackgound)
{
IPaintControl parent = Parent as IPaintControl;
if (parent != null)
{
parent.InvokePaintBackground(e);
}
}
else base.OnPaintBackground(e);
}
}
现在我们可以使用以下代码创建透明标签控件
public class CcTransparentLabel : CcTransparentControl
{
private ContentAlignment textAlign = ContentAlignment.TopLeft;
public ContentAlignment TextAlign
{
get
{
return textAlign;
}
set
{
textAlign = value;
}
}
public CcTransparentLabel()
{
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics gfx = e.Graphics;
if (this.TextAlign == ContentAlignment.TopLeft)
{
gfx.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), ClientRectangle);
}
else if (this.TextAlign == ContentAlignment.TopCenter)
{
SizeF size = gfx.MeasureString(this.Text, this.Font);
int left = this.Width / 2 - (int)size.Width / 2;
var rect = new Rectangle(ClientRectangle.Left + left,
ClientRectangle.Top, (int)size.Width,
ClientRectangle.Height);
gfx.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), rect);
}
else if (this.TextAlign == ContentAlignment.TopRight)
{
SizeF size = gfx.MeasureString(this.Text, this.Font);
int left = this.Width - (int)size.Width + this.Left;
var rect = new Rectangle(ClientRectangle.Left + left,
ClientRectangle.Top, (int)size.Width,
ClientRectangle.Height);
gfx.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), rect);
}
}
}
在我们的窗体中,我们将窗体更改为继承自 CcForm
并将 CcTransparentLabel
拖放到它上面。
public partial class FormWithSolidColorBackground : CcForm
这是屏幕截图。正如您所看到的,标签现在具有透明背景。

但是,当我尝试添加具有渐变颜色的图像背景时,我的标签看起来不再正确。

要了解这个问题,我们需要首先看看我们如何在窗体上显示背景图像。
public partial class FormWithImageBackground : CcForm
{
private Rectangle _backgroundRect;
private Bitmap _background;
private string currentPath = Path.GetDirectoryName
(Assembly.GetExecutingAssembly().GetName().CodeBase.ToString());
public FormWithImageBackground()
{
InitializeComponent();
_background = new Bitmap(currentPath + @"\ImageBackground.jpg");
_backgroundRect = new Rectangle(0, 0, _background.Width, _background.Height);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(_background, this.ClientRectangle,
_backgroundRect, GraphicsUnit.Pixel);
}
}
发生的事情是,当透明标签控件调用 OnPaintBackground
时,它会重新绘制标签控件内的图像。因此,它在标签的背景上显示图像的左上角。为了解决这个问题,我将标签控件的位置传递给窗体,并使用它来重新绘制图像。例如,如果标签位于 (10, 20),则图像背景将显示在 (-10, -20)。这可能不是最好的解决方案,但它很简单而且有效。 这是修改后的接口和控件。
public interface IPaintControl
{
// have the background painted
void InvokePaintBackground(PaintEventArgs e, Point location);
}
public class CcForm : Form, IPaintControl
{
public virtual void InvokePaintBackground(PaintEventArgs e, Point location)
{
OnPaintBackground(e);
}
}
public class CcTransparentControl : Control
{
....
protected override void OnPaintBackground(PaintEventArgs e)
{
if (_transparentBackgound)
{
IPaintControl parent = Parent as IPaintControl;
if (parent != null)
{
parent.InvokePaintBackground(e, this.Location);
}
}
else base.OnPaintBackground(e);
}
}
在窗体中,我然后覆盖 InvokePaintBackground
方法以在所需位置绘制图像。
public override void InvokePaintBackground
(System.Windows.Forms.PaintEventArgs e, System.Drawing.Point location)
{
Graphics g = e.Graphics;
Rectangle destRect = new Rectangle(-1 * location.X, -1 * location.Y,
ClientRectangle.Width, ClientRectangle.Height);
g.DrawImage(_background, destRect, _backgroundRect, GraphicsUnit.Pixel);
}
现在我们有一个覆盖图像背景的透明标签。

我还创建了一个透明单选按钮和复选框控件。这些是在窗体中常用的控件,Panel
控件也是如此。以下示例显示了透明面板上的透明单选按钮和复选框。

编程愉快!
历史
- 2009 年 10 月 8 日:首次发布
- 2009 年 10 月 9 日:文章已更新