通过继承Control控件类,进行重写,实现Layer效果的遮罩层,具体使用可直接看后面的介绍。
功能介绍和代码实现
主要功能如下:
- 遮罩层的透明度
Alpha
,默认125。255表示不透明。 - 设置遮罩层中心的图片
LayerImage
,默认无。通常为加载效果的gif图片。 - 遮罩层中心的图片的大小,
LayerImageWidth
、LayerImageHeight
,默认为图片大小。 - 遮罩层上的控件
ControlOnLayer
。此处实现不严谨,通过此属性可以添加多个控件进入,通常一个即可。如果有控件,则中间的图片将不显示。 - 遮罩层的颜色
LayerColor
,默认为Gray。 - 推荐使用
Parent
设置其父控件。
关于加载图片的背景透明:图片背景透明的效果和base.BackColor
有关(即控件的背景,因此需要透明)。但并未做到真正透明底部的内容。因此,设置
base.BackColor
为透明色,且不允许外部修改BackColor
。
/// <summary>
/// 自定义控件:半透明控件
/// </summary>
/*
* [ToolboxBitmap(typeof(MyOpaqueLayer))]
* 用于指定当把你做好的自定义控件添加到工具栏时,工具栏显示的图标。
* 正确写法应该是
* [ToolboxBitmap(typeof(XXXXControl),"xxx.bmp")]
* 其中XXXXControl是你的自定义控件,"xxx.bmp"是你要用的图标名称。
*/
[ToolboxBitmap(typeof(CMLayer))]
public class CMLayer : Control
{
private int _alpha;//设置透明度 255表示不透明
private PictureBox loadingPicBox;// 加载图片
private Control controlOnLayer;//遮罩上的控件
private Color layerColor;
[Category("高级"), DefaultValue(125), Description("设置遮罩层透明度,默认125。255表示不透明")]
public int Alpha
{
get
{
return _alpha;
}
set
{
_alpha = value;
this.Invalidate();
}
}
/// <summary>
/// 图片背景透明的效果和base.BackColor有关(控件背景,因此需要透明)。但并未做到真正透明底部的内容
/// </summary>
[Category("高级"), Description("遮罩层中间显示的图片,默认无。通常为加载效果的gif图片")]
public Image LayerImage
{
get => loadingPicBox?.Image;
set
{
if (value != null && loadingPicBox == null)
{
loadingPicBox = new PictureBox()
{
SizeMode = PictureBoxSizeMode.Zoom,
BackColor = Color.Transparent,
//Margin = new Padding(0)
};
loadingPicBox.Width = value.Width;
loadingPicBox.Height = value.Height;
loadingPicBox.Location = new Point((Width - loadingPicBox.Width) / 2, (Height - loadingPicBox.Height) / 2);
Controls.Add(loadingPicBox);
}
if (loadingPicBox != null)
{
loadingPicBox.Image = value;
if (controlOnLayer != null)
{
loadingPicBox.Visible = false;
}
}
}
}
[Category("高级"), Description("遮罩层中间显示的图片的宽度,默认为图片大小")]
public int LayerImageWidth { get { return loadingPicBox?.Width ?? 0; } set { if (loadingPicBox != null) loadingPicBox.Width = value; } }
[Category("高级"), Description("遮罩层中间显示的图片的高度,默认为图片大小")]
public int LayerImageHeight { get { return loadingPicBox?.Height ?? 0; } set { if (loadingPicBox != null) loadingPicBox.Height = value; } }
[Category("高级"), Description("遮罩层中间显示的控件,默认无。如果有控件,则中间的图片将不显示")]
public Control ControlOnLayer
{
get => controlOnLayer; set
{
controlOnLayer = value;
controlOnLayer.Location = new Point((Width - controlOnLayer.Width) / 2, (Height - controlOnLayer.Height) / 2);
Controls.Add(controlOnLayer);
controlOnLayer.BringToFront(); // 非必须
if (loadingPicBox != null && loadingPicBox.Visible)
{
loadingPicBox.Visible = false;
}
}
}
[Category("高级"), DefaultValue(typeof(Color), "Gray"), Description("遮罩层的颜色")]
public Color LayerColor
{
get
{
return Color.FromArgb(_alpha, layerColor);
}
set
{
layerColor = value;
Invalidate();
}
}
public new Control Parent
{
get
{
return base.Parent;
}
set
{
base.Parent = value;
if (value != null)
{
Dock = DockStyle.Fill;
BringToFront();
}
}
}
[Browsable(false), Description("隐藏背景色的更改")]
public override Color BackColor => base.BackColor;
public CMLayer() : this(125)
{
}
public CMLayer(int alpha)
{
SetStyle(System.Windows.Forms.ControlStyles.Opaque | ControlStyles.SupportsTransparentBackColor, true);
base.CreateControl();
this._alpha = alpha;
base.BackColor = Color.Transparent;
LayerColor = Color.Gray;
Dock = DockStyle.Fill;
BringToFront();
}
/// <summary>
/// 自定义绘制背景
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
SolidBrush backBrush = new SolidBrush(LayerColor);
e.Graphics.FillRectangle(backBrush, ClientRectangle);
}
}
遮罩层的使用
- 创建添加到窗体并显示
var layer = new CMLayer();
this.Controls.Add(layer); // Add 需调用BringToFront
layer.BringToFront();
layer.Show();
- 推荐Parent赋值
layer.Parent = this;
- 修改颜色
layer.LayerColor = Color.MediumPurple;
- 遮罩层中间添加加载效果的图片
layer.LayerImage = LoadingImg.LoadingSimple;
//layer.LayerImage = LoadingImg.LoadingStripBar;
//layer.LayerImage = LoadingImg.LoadingStripBar2;
layer.LayerColor = Color.CornflowerBlue;
ControlOnLayer
遮罩层中间添加控件
将一个ProgressBar控件添加到遮罩层
using (var layer = new CMLayer())
{
// 推荐Parent
layer.Parent = this;
// 显示操作进度
using (var progressBar = new ProgressBar())
{
#region 遮罩层上添加一个progressBar【ControlOnLayer属性的方式】
progressBar.Style = ProgressBarStyle.Marquee;
progressBar.Width = layer.Width - 10;
layer.ControlOnLayer = progressBar;
#endregion
layer.LayerColor = Color.CornflowerBlue;
layer.Show();
// 处理耗时的操作,最好使用异步...
}
layer.Hide();
}
layer.Controls.Add
向遮罩层添加控件
#region 遮罩层上添加一个progressBar【layer.Controls.Add的方式】
progressBar.Style = ProgressBarStyle.Marquee;
progressBar.Width = layer.Width - 10;
// 居中
progressBar.Location = new Point((layer.Width - progressBar.Width) / 2, (layer.Height - progressBar.Height) / 2);
layer.Controls.Add(progressBar);
progressBar.BringToFront();
#endregion
一些问题
- 无法在设计器中很好的使用。在窗体设计器中使用时,调整大小或移动、修改颜色时,总会使的遮罩层不透明。暂时无法解决。
- 控件添加时注意层次,通过
BringToFront()
显示到最前方。 - 未添加关闭按钮,可根据需要在遮罩层上添加关闭按钮。否则代码中要就保证会自动关闭。
- 遮罩层的大小问题,控件只能位于窗体内,因此遮罩层控件无法遮盖整个窗体,遮罩层只显示在窗体内。
通常开启遮罩层是为了等待耗时操作,因此,开启遮罩层后,最好禁止关闭。如果能够遮住整个窗体,那么就这遮住了顶部菜单栏的关闭按钮,也能实现禁止关闭,并且效果比较好。