之前介绍了通过继承Control控件类实现遮罩层的方法,但相对来说有些不如意的地方,最大的缺点是无法遮盖整个窗体【不过也不算缺点,对于浏览器中常见的web遮罩层,也是遮罩的当前整个页面,而无法覆盖到整个浏览器上】
对于完全由自己控制实现的桌面应用来说,则可以想办法实现遮罩整个窗体(窗口)的Layer层。下面介绍在Winform中利用Form做遮罩层的实现,推荐的还是第二种方式:双Form的遮罩层。
遮罩层实现二【继承Form利用Opacity实现】
Winform应用程序实现通用遮罩层介绍了通过Form的Opacity属性,实现类似遮罩效果的窗体。
但是,由于Opacity
透明的是整个窗体,包括窗体里面的控件,所以总体不推荐这种方式。而且原文感觉实现得有些复杂...
有几点可以后续深入了解下:
- 设置遮罩层的大小。通过Form窗体实现的遮罩可以覆盖后面的整个主窗体。对于耗时等待来说更合理(即将关闭、最大、最小化等操作禁止)。
- 动态对象
ExpandoObject
的实现,虽然文中没有任何使用。但是其无法通过委托传递参数到另一个方法内获取数据。也就是ExpandoObject
只能在一个上下文中使用。后续可深入了解。 ImageAnimator
动画处理包括时间的帧的图像,位于System.Drawing
命名空间下,用于处理和获取逐帧动画内的图像,ImageAnimator.Animate(image, evtHandler);
将多帧图像显示为动画,即逐帧显示,并提供每帧的事件处理器,然后使用CreateGraphics().DrawImage
绘制每帧图像,实现动画效果。
遮罩层实现三【双Form利用Opacity实现】
利用Form的Opacity
实现遮罩层的一个很大的问题就是透明,它是针对整个窗体(包括其中的子控件)的透明,而我们需要的是背景透明。
因此,可以在透明窗体的基础上再添加一个Form窗体,用来放置要显示的其他内容。
LayerForm
构造函数的第一个参数LayeredForm
为要遮住的窗体;onLayerForm
为位于遮罩之上的弹窗窗体。
代码很简单,如下:
public class LayerForm:Form
{
private Form _onLayerForm;
public LayerForm(Form LayeredForm,Form onLayerForm)
{
ControlBox = false;
FormBorderStyle = FormBorderStyle.FixedSingle;
StartPosition = FormStartPosition.Manual;
BackColor = Color.Black;
Opacity = 0.5;
ShowInTaskbar = false;
Location = LayeredForm.Location;
Size = LayeredForm.Size;
_onLayerForm = onLayerForm;
//Load += LayerForm_Load; // Load中处理不显示onLayerForm —— _onLayerForm.ShowDialog()
Shown += LayerForm_Shown;
}
private void LayerForm_Shown(object sender, EventArgs e)
{
_onLayerForm.ShowInTaskbar = false;
_onLayerForm.StartPosition = FormStartPosition.CenterParent;
_onLayerForm.FormClosed += OnLayerForm_FormClosed;
_onLayerForm.ShowDialog();
}
private void OnLayerForm_FormClosed(object sender, FormClosedEventArgs e)
{
this.Close();
}
}
使用就非常简单了。
将显示在遮罩层上的窗体传递进去即可:
var onLayerForm = new OnLayerForm();
var layerForm = new LayerForm(this, onLayerForm);
layerForm.Show(); // 推荐Show();
遮罩上的窗体可根据需要设置或加入加载动画、处理逻辑、必要的控件等。
遮罩上的窗体显示使用 _onLayerForm.ShowDialog()
以对话框模式显示,可以做到居中位置的实现。
可以适当修改FormBorderStyle
,使遮罩层完全贴合窗体的大小。
遮罩窗体layerForm
推荐使用Show()
显示,后续可在外部调用Close()
关闭遮罩层窗体。如果使用layerForm.ShowDialog()
通常会导致当前(UI线程)的处理阻塞,因此需要提前在子线程中启动耗时的操作,以及在操作完成后正确处理(关闭)显示的遮罩层。
var onLayerForm = new OnLayerForm();
var layerForm = new LayerForm(this, onLayerForm);
layerForm.Show();
var timer = new System.Windows.Forms.Timer();
// timer.Interval = 100;
timer.Tick += (t, ea)=> {
// 处理耗时操作...
timer.Stop();
// 处理完耗时操作,关闭Layer窗体
layerForm.Close();
};
timer.Start();