制作可自定义风格的winform组件类(三)基类

一个良好的基类能决定这个控件能走多远,那么下面来定义一些事情。

定义状态,表示控件当前处于哪种状态,用来区别对同一事件作出不同的响应

    [Flags]
    public enum CDControlState
    {
        None = 0,
        SkinLoaded = 1,
        MouseEnter = 2,
        MouseDown = 4,
        Resizing = 8,
    }

定义事件,用来定制需求,忽略无用的代码,以免造成过多响应或是窗口重绘

    [Flags]
    public enum CDControlEvent
    {
        None = 0,
        MouseMove = 1,
        MouseClick = 2,
        BackImage = 4,
        BackColor = 8,
        Text = 0x10,
        Icon = 0x20,
    }

再来定义一个接口,这是为了实现一键换肤功能,把装载素材和重定位控件内结构分别对待,同时还要在设计时把素材装填到控件相对应的属性并显示在IDE中

    public interface ICDSkin
    {
        void SkinLoad();
        void DesigntimeSkinLoad(string name);
        void CaculateLocation();
    }

回到正题,来说说基类吧,基本雏形代码是下面这样的

namespace CDTheme
{
    [ToolboxItem(false)]
    public abstract partial class CDBase : UserControl, ICDSkin
    {
        private bool _isLoaded;
        private CDControlState _cdState;
        private CDControlEvent _cdEvent;
        protected bool IsLoaded
        {
            get
            {
                return _isLoaded;
            }
        }
        protected CDControlState CDState
        {
            get
            {
                return _cdState;
            }
        }
        protected CDControlEvent CDEvent
        {
            get
            {
                return _cdEvent;
            }
        }
        private void SetCDControlState(CDControlState state, bool allow)
        {
            if (allow)
                _cdState |= state;
            else
                _cdState &= ~state;
        }
        protected void SetCDControlEvent(CDControlEvent style, bool allow)
        {
            if (allow)
                _cdEvent |= style;
            else
                _cdEvent &= ~style;
        }

        public void DesigntimeSkinLoad(string name)
        {
            CDSkinManager.DesigntimeSkinLoad(this, name);
        }

        public virtual void SkinLoad()
        {
            SetCDControlState(CDControlState.SkinLoaded, true);
        }

        public virtual void CaculateLocation()
        {
        }

protected virtual void StateChanged(CDControlState changedState, bool allow)
        {
            SetCDControlState(changedState, allow);
        }

        public CDBase()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
            InitializeComponent();
        }

        [Browsable(false)]
        public new BorderStyle BorderStyle
        {
            get
            {
                return base.BorderStyle;
            }
            set
            {
                base.BorderStyle = value;
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            _isLoaded = true;
            base.OnLoad(e);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (CDState.HasFlag(CDControlState.SkinLoaded))
                CaculateLocation();
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);
            StateChanged(CDControlState.None, true);
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            if (CDEvent.HasFlag(CDControlEvent.MouseMove))
                StateChanged(CDControlState.MouseEnter, true);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (CDEvent.HasFlag(CDControlEvent.MouseMove))
                StateChanged(CDControlState.MouseEnter, false);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (e.Button == MouseButtons.Left)
                if (CDEvent.HasFlag(CDControlEvent.MouseClick))
                    StateChanged(CDControlState.MouseDown, false);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == MouseButtons.Left)
                if (CDEvent.HasFlag(CDControlEvent.MouseClick))
                    StateChanged(CDControlState.MouseDown, true);
        }
    }
}

虽然没有注释,但通过名称大家也能明白意思,封装了常用的事件并统一到StateChanged方法中,让派生类通过重写此方法来作出独立的响应

那么如何使用这个基类?

一、在每个在有实际代码派生类的构造函数中使用SetCDControlEvent来决定当些事件会被响应

二、通过重写SkinLoad、CaculateLocation与StateChanged三个方法,来达到装载素材、重新定位与事件响应的效果

三、根据需求定义属性与实现界面的逻辑

说得很抽象,在下一篇将会给出一个简单的实例来说明

时间: 2024-08-23 22:05:04

制作可自定义风格的winform组件类(三)基类的相关文章

制作可自定义风格的winform组件类(四)简单按钮

实际上这并不是一个按钮,只是一个变换背影图层而已,但通过过滤背景色,它实现了按钮的不规则形态,例如最常见的圆角风格,下面是代码 namespace CDTheme { public abstract partial class CDBaseImage : CDBase { private Image _normalImage; private Image _disabledImage; public CDBaseImage() { InitializeComponent(); } [Browsa

制作可自定义风格的winform组件类(二)知识要点总结

本文不断补充中,这全都是浪费了我很多时间才走过的坎 一.继承关系. 所有自定义的控件都继承自UserControl,当然你也可以直接从标准的winform控件中派生新类,但这样生出来的控件不能在设计时使用,所以还是得规规矩矩的按.NET给定的路线走.UserControl继承于标准控件的基类Control,使得用户自定义的控件与标准控件在运行时没有任何差别,但在设计时却有很大的不同,有些属性被override后不起作用,似乎是IDE认准了原来属性的get和set方法,对策就是隐藏这个属性,然后用

制作可自定义风格的winform组件类(一)准备工作

首先要明确目的,就是这组控件打算做成什么样子,都有哪些功能.我的计划如下: 一.公共的控件类,并且方便扩展 二.控件的外观素材与控件本身分离,并使外观效果更易于更新替换 三.支持一鍵换肤功能,这包括运行时与设计时 四.做一个控件皮肤风格设计器并支持多种部署方案 准备所需要的内容: 一.VS2013(废话) 二.一套默认的控件皮肤,本人的平面设计能力基本为零,所以一定是在网上摘来的,很无奈,大部分素材都是为web而生,应用在winform上总是少一种状态 三.基于上一点,所以又下载了中文PS,妄想

C++的继承操作---基类指针访问派生类问题---基类成员恢复访问属性问题

#include "stdafx.h" #include <iostream> #include <algorithm> using namespace std; class Base { public: int num; virtual void func() { cout<<"Do something in Base"<<endl; } }; class Derived:private Base { public:

派生类到基类转换的可访问性

      从派生类到基类的转换的可访问性取决于派生类的派生列表中指定的访问标号. 要确定到基类的转换是否可访问,可以考虑基类的public成员是否可以访问, 如果可以,转换是可访问的,否则,转换是不可访问的. 如果是public继承,则用户代码和后代类都可以使用派生类到基类的转换: 如果是private或protected继承,则用户代码不能将派生对象类转换到基类对象: 注:如果是protected继承,则后续派生类的成员可以转换为基类类型.

一步一步搭建开发框架(三)基类基接口

1,AdoNetDal和EfDal都实现IDal这个接口,公共的方法写到接口中,接口中的代码! 1 namespace PCITC.OA.IDal 2 { 3 public interface IUserInforDal 4 { 5 UserInfor Add(UserInfor userInfor); 6 7 bool Update(UserInfor userInfor); 8 9 bool Delete(UserInfor userInfor); 10 11 int Delete(para

c++——派生类和基类转换

派生类经常(但不总是)覆盖它继承的虚函数.如果派生类没有覆盖其基类中的某个虚函数,则该虚函数的行为类似于其他的普通成员,派生类会直接继承其在基类中的版本. c++11允许派生类显式地注明它使用某个成员函数覆盖了它继承的虚函数.具体做法是在形参列表后面.或者在const成员函数的const关键字后面.或者在引用成员函数的引用限定符后面添加一个关键字override. 派生类也必须使用基类的构造函数来初始化它的基类部分.(除非基类没有显式定义构造函数,这样在派生类的构造函数中可以不显式调用基类的构造

c++中派生类对基类成员的三种访问规则(转)

C++中派生类对基类成员的访问形式主要有以下两种:1.内部访问:由派生类中新增成员对基类继承来的成员的访问.2.对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问.今天给大家介绍在3中继承方式下,派生类对基类成员的访问规则. 1.私有继承的访问规则当类的继承方式为私有继承时,基类的public成员和protected成员被继承后成为派生类的private成员,派生类的其它成员可以直接访问它们,但是在类的外部通过派生类的对象无法访问.基类的private成员在私有派生类中是不可直接

C++派生类与基类的转换规则

基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,具体表现在以下几个方面,需要的朋友可以参考下 只有公用派生类才是基类真正的子类型,它完整地继承了基类的功能.基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将派生类的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替. 具体表现在以下几个方面: 派生类对象可以向基类对象赋值. 可以用子类(即公用派生类)对象对其基类对象赋值.如 A a1; //定义基类A对象a1 B b1; //定义类A的公