Winform控件优化之继承Control重写实现Layer遮罩层

简介: 通过继承Control控件类,进行重写,实现Layer效果的遮罩层,具体使用可直接看后面的介绍。主要功能如下:1. 遮罩层的透明度Alpha,默认125。255表示不透明。2. 设置遮罩层中心的图片

通过继承Control控件类,进行重写,实现Layer效果的遮罩层,具体使用可直接看后面的介绍。

功能介绍和代码实现

主要功能如下:

  1. 遮罩层的透明度Alpha,默认125。255表示不透明。
  2. 设置遮罩层中心的图片LayerImage,默认无。通常为加载效果的gif图片。
  3. 遮罩层中心的图片的大小,LayerImageWidthLayerImageHeight,默认为图片大小。
  4. 遮罩层上的控件ControlOnLayer。此处实现不严谨,通过此属性可以添加多个控件进入,通常一个即可。如果有控件,则中间的图片将不显示。
  5. 遮罩层的颜色LayerColor,默认为Gray。
  6. 推荐使用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

一些问题

  1. 无法在设计器中很好的使用。在窗体设计器中使用时,调整大小或移动、修改颜色时,总会使的遮罩层不透明。暂时无法解决。
  2. 控件添加时注意层次,通过BringToFront()显示到最前方。
  3. 未添加关闭按钮,可根据需要在遮罩层上添加关闭按钮。否则代码中要就保证会自动关闭。
  4. 遮罩层的大小问题,控件只能位于窗体内,因此遮罩层控件无法遮盖整个窗体,遮罩层只显示在窗体内。

通常开启遮罩层是为了等待耗时操作,因此,开启遮罩层后,最好禁止关闭。如果能够遮住整个窗体,那么就这遮住了顶部菜单栏的关闭按钮,也能实现禁止关闭,并且效果比较好。

参考

相关文章
Winform控件优化之双层Form利用Opacity实现Layer遮罩层
对于完全由自己控制实现的桌面应用来说,则可以想办法实现遮罩整个窗体(窗口)的Layer层。下面介绍在Winform中利用Form做遮罩层的实现,推荐的还是第二种方式:双Form的遮罩层....
272 0
Winform控件优化之双层Form利用Opacity实现Layer遮罩层
|
前端开发 C#
【C#/WPF】ListView的MVVM例子,及禁止拖动ListView的头部Header
原文:【C#/WPF】ListView的MVVM例子,及禁止拖动ListView的头部Header 一个ListView的MVVM简单例子: ...
1606 0
|
API Windows 容器
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件(上)
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件
204 0
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件(上)
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件(下)
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件
168 0
Qt Designer设置背景图片、颜色不影响其它组件小技巧,控件层级设置,组件的继承,styleSheet设置样式。
Qt Designer设置背景图片、颜色不影响其它组件小技巧,控件层级设置,组件的继承,styleSheet设置样式。
783 0
Qt Designer设置背景图片、颜色不影响其它组件小技巧,控件层级设置,组件的继承,styleSheet设置样式。
|
C#
WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探
原文:WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探         最近因为项目需要,开始学习如何使用WPF开发桌面程序。
1561 0
|
C# Windows
WPF 4 动态覆盖图标(Dynamic Overlay Icon)
原文:WPF 4 动态覆盖图标(Dynamic Overlay Icon)      在《WPF 4 开发Windows 7 任务栏》一文中我们学习了任务栏的相关开发内容,同时也对覆盖图标(Overlay Icon)功能进行了一些介绍,其中覆盖图标是以静态方式呈现的。
1128 0
|
C#
WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性
原文:WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性 如果你要自定义一个图片按钮控件,那么如何在主窗体绑定这个控件上图片的Source呢? 我向大家介绍一个用 依赖属性(DependencyProperty) 实现的方法。
2492 0
|
Windows
背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素
原文:背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素 [源码下载] 背水一战 Windows 10 (76) - 控件(控件基类): Control -...
1145 0