苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper爬虫框架(V2.3-含.netcore) HttpHelper官方出品,爬虫框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 开源的爬虫类,支持多种模式和属性 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 14180|回复: 2

[C#皮肤] C#皮肤-ComboBox 控件实现

[复制链接]
发表于 2013-3-5 10:35:54 | 显示全部楼层 |阅读模式
找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里联系我
                C#皮肤-ComboBox 控件实现

导读部分
-------------------------------------------------------------------------------------------------------------
C#皮肤-实现原理系列文章导航
http://www.sufeinet.com/thread-2-1-1.html

这个控件是在系统控件ComboBox的基础之上来实现的,我们先来看一下实现后的效果
ComboBox1.png          ComboBox2.png
这是实现 后的效果,与普通的不同之处有,颜色有所变化,倒三角有所变化,再就是有一个鼠标跟随的效果。下面我来看看是怎么样实现的吧。  我们第一步要打开我们的项目,然后右击项目,新添加一个Component组件。然后继承一下Combox类
代码如下
[code=csharp] public class ComboBox : System.Windows.Forms.ComboBox[/code]
下面我们先定义几个变量
[code=csharp]//鼠标Move事件时图片
        private Image _mouseMoveImage = null;

        //鼠标mouseDown事件时图片
        private Image _mouseDownImage = null;
        //
        private Image _normalImage = null;[/code]
下面我看看再在构造方法里设置一下些固定的属性
[code=csharp] public ComboBox()
            : base()
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            //设置为手动绘制
            this.DrawMode = DrawMode.OwnerDrawFixed;
            //设置固定的DropDownList样式
            this.DropDownStyle = ComboBoxStyle.DropDownList;
            this.UpdateStyles();
        }[/code]
为了让控件里的项目大小一至方便绘制和添加效果我们要重写一下OnCreateControl方法来固定一下Item的大小
[code=csharp] protected override void OnCreateControl()
        {
            base.OnCreateControl();
            if (!DesignMode && this.Items.Count != 0)
            {
                this.DropDownHeight = this.Items.Count * 17;
            }
            ResetBitmap();
        }[/code]
ResetBitmap()方法就是用来设置不同情况下的颜色的
[code=csharp] public void ResetBitmap()
        {
            this.NormalImage = Shared.NomalDrawButton;
            this.MouseDownImage = Shared.MouseDownDrawButton;
            this.MouseMoveImage = Shared.MouseMoveDrawButton;
        }[/code]

Shared类的方法和属性请大家参考源代码里的 ,源代码的下载在 http://www.sufeinet.com/thread-2-1-1.html   
   这里都有提供。
下面还是老规矩重写一下WndProc方法吧,
[code=csharp]protected override void WndProc(ref Message m)
        {
            IntPtr hDC = IntPtr.Zero;
            Graphics gdc = null;

            switch (m.Msg)
            {
                case 133:
                    hDC = Win32.GetWindowDC(m.HWnd);
                    gdc = Graphics.FromHdc(hDC);
                    Win32.SendMessage(this.Handle, WM_ERASEBKGND, hDC.ToInt32(), 0);
                    SendPrintClientMsg();
                    Win32.SendMessage(this.Handle, WM_PAINT, 0, 0);
                    OverrideControlBorder(gdc);
                    m.Result = (IntPtr)1;    // indicate msg has been processed
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    break;
                case WM_PAINT:
                    base.WndProc(ref m);
                    hDC = Win32.GetWindowDC(m.HWnd);
                    gdc = Graphics.FromHdc(hDC);

                    OverrideDropDown(gdc);
                    OverrideControlBorder(gdc);
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }[/code]
因为我们的图片颜色是手动绘制上去的所以我们应该在OverrideDropDown方法里进行绘制,也就是说当我们出现下拉列表的时候要绘制一下效果。
[code=csharp] private void OverrideDropDown(Graphics g)
        {
            if (DesignMode) return;

            Rectangle rect = new Rectangle(this.Width - DropDownButtonWidth, 0, DropDownButtonWidth, this.Height);

            g.FillRectangle(new SolidBrush(Color.White), rect);

            if (this.Enabled)
            {
                if (_mouseEnter)
                {
                    g.DrawImage(this.MouseMoveImage, new Rectangle(this.Width - 20, 3, 16, 16));
                }
                else
                {
                    g.DrawImage(this.NormalImage, new Rectangle(this.Width - 20, 3, 16, 16));
                }
            }
            else
            {
                g.DrawImage(Shared.NotEnableDrawButton, new Rectangle(this.Width - 20, 3, 16, 16));
            }
        }[/code]

根据鼠标的状态不同绘制出不同的效果,大家看一下If语句 就明白 了
还有一个更重的方法就是OnDrawItem方法这是在加载时绘制一下初始化的效果
[code=csharp] protected override void OnDrawItem(DrawItemEventArgs e)
        {
            Graphics g = e.Graphics;
            //绘制区域
            Rectangle r = e.Bounds;

            Font fn = null;
            if (e.Index >= 0)
            {
                if (e.State == DrawItemState.None)
                {
                    //设置字体、字符串格式、对齐方式
                    fn = e.Font;
                    string s = this.Items[e.Index].ToString ();
                    StringFormat sf = new StringFormat();
                    sf.Alignment = StringAlignment.Near;
                    //根据不同的状态用不同的颜色表示
                    if (e.State == (DrawItemState.NoAccelerator | DrawItemState.NoFocusRect))
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.Red), r);
                        e.Graphics.DrawString(s, fn, new SolidBrush(Color.Black), r, sf);
                        e.DrawFocusRectangle();
                    }
                    else
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.White), r);
                        e.Graphics.DrawString(s, fn, new SolidBrush(Shared.FontColor), r, sf);
                        e.DrawFocusRectangle();
                    }
                }
                else
                {
                    fn = e.Font;
                    StringFormat sf = new StringFormat();
                    sf.Alignment = StringAlignment.Near;
                    string s = this.Items[e.Index].ToString ();
                    e.Graphics.FillRectangle(new SolidBrush(Shared.ControlBackColor), r);
                    e.Graphics.DrawString(s, fn, new SolidBrush(Shared.FontColor), r, sf);
                    
                }
            }
        }[/code]

有了这些我们现在要做的就是在OnMouseEnter事件OnMouseLeave事件里处理一下绘制的效果和参数就算是完工了
我们一起来看看这两个事件的处理方法吧
[code=csharp]protected override void OnMouseEnter(EventArgs e)
        {
            _mouseEnter = true;

            IntPtr hDC = IntPtr.Zero;
            Graphics gdc = null;
            hDC = Win32.GetWindowDC(this.Handle);
            gdc = Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.MouseMoveDrawButton, new Rectangle(this.Width - 20, 3, 16, 16));

            Win32.ReleaseDC(this.Handle, hDC);
            gdc.Dispose();

            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            _mouseEnter = false;
            IntPtr hDC = IntPtr.Zero;
            Graphics gdc = null;
            hDC = Win32.GetWindowDC(this.Handle);
            gdc = Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.NomalDrawButton, new Rectangle(this.Width - 20, 3, 16, 16));

            Win32.ReleaseDC(this.Handle, hDC);
            base.OnMouseLeave(e);
        }[/code]

到这里其实就可以完工了,其它的方法和事件都是一相辅助,等下可以看一下全部代码。
具体的使用方法和系统的Combox控件没有任何的分别。直接绑定数据就OK了。
为了方便以后的改动我把三个效果时产生的图片都定义成属性大家使用起来会方便一些
[code=csharp]public Image MouseMoveImage
        {
            get
            {
                return _mouseMoveImage;
            }
            set
            {
                _mouseMoveImage = value;
            }
        }

        public Image MouseDownImage
        {
            get
            {
                return _mouseDownImage;
            }
            set
            {
                _mouseDownImage = value;
            }
        }

        public Image NormalImage
        {
            get
            {
                return _normalImage;
            }
            set
            {
                _normalImage = value;
            }
        }[/code]
整个类的代码如下
[code=csharp]using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CRD.Common;

namespace CRD.WinUI.Misc
{
    public class ComboBox : System.Windows.Forms.ComboBox
    {
        //鼠标Move事件时图片
        private Image _mouseMoveImage = null;

        //鼠标mouseDown事件时图片
        private Image _mouseDownImage = null;
        //
        private Image _normalImage = null;


        public ComboBox()
            : base()
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            //设置为手动绘制
            this.DrawMode = DrawMode.OwnerDrawFixed;
            //设置固定的DropDownList样式
            this.DropDownStyle = ComboBoxStyle.DropDownList;
            this.UpdateStyles();
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            if (!DesignMode && this.Items.Count != 0)
            {
                this.DropDownHeight = this.Items.Count * 17;
            }
            ResetBitmap();
        }

        const int WM_ERASEBKGND = 0x14;
        const int WM_PAINT = 0xF;
        const int WM_NC_HITTEST = 0x84;
        const int WM_NC_PAINT = 0x85;
        const int WM_PRINTCLIENT = 0x318;
        const int WM_SETCURSOR = 0x20;

        protected override void WndProc(ref Message m)
        {
            IntPtr hDC = IntPtr.Zero;
            Graphics gdc = null;

            switch (m.Msg)
            {
                case 133:
                    hDC = Win32.GetWindowDC(m.HWnd);
                    gdc = Graphics.FromHdc(hDC);
                    Win32.SendMessage(this.Handle, WM_ERASEBKGND, hDC.ToInt32(), 0);
                    SendPrintClientMsg();
                    Win32.SendMessage(this.Handle, WM_PAINT, 0, 0);
                    OverrideControlBorder(gdc);
                    m.Result = (IntPtr)1;    // indicate msg has been processed
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    break;
                case WM_PAINT:
                    base.WndProc(ref m);
                    hDC = Win32.GetWindowDC(m.HWnd);
                    gdc = Graphics.FromHdc(hDC);

                    OverrideDropDown(gdc);
                    OverrideControlBorder(gdc);
                    Win32.ReleaseDC(m.HWnd, hDC);
                    gdc.Dispose();
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        private static int DropDownButtonWidth = 17;

        private void OverrideDropDown(Graphics g)
        {
            if (DesignMode) return;

            Rectangle rect = new Rectangle(this.Width - DropDownButtonWidth, 0, DropDownButtonWidth, this.Height);

            g.FillRectangle(new SolidBrush(Color.White), rect);

            if (this.Enabled)
            {
                if (_mouseEnter)
                {
                    g.DrawImage(this.MouseMoveImage, new Rectangle(this.Width - 20, 3, 16, 16));
                }
                else
                {
                    g.DrawImage(this.NormalImage, new Rectangle(this.Width - 20, 3, 16, 16));
                }
            }
            else
            {
                g.DrawImage(Shared.NotEnableDrawButton, new Rectangle(this.Width - 20, 3, 16, 16));
            }
        }

        private Pen BorderPen = new Pen(Shared.ControlBorderBackColor, 2);
        private Pen BorderPenControl = new Pen(Shared.ControlBorderBackColor, 2);

        private void OverrideControlBorder(Graphics g)
        {
            g.DrawRectangle(new Pen(Shared.ControlBorderBackColor, 2), new Rectangle(0, 0, this.Width, this.Height));

        }

        private void SendPrintClientMsg()
        {
            // We send this message for the control to redraw the client area
            Graphics gClient = this.CreateGraphics();
            IntPtr ptrClientDC = gClient.GetHdc();
            Win32.SendMessage(this.Handle, WM_PRINTCLIENT, ptrClientDC.ToInt32(), 0);
            gClient.ReleaseHdc(ptrClientDC);
            gClient.Dispose();
        }


        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            Graphics g = e.Graphics;
            //绘制区域
            Rectangle r = e.Bounds;

            Font fn = null;
            if (e.Index >= 0)
            {
                if (e.State == DrawItemState.None)
                {
                    //设置字体、字符串格式、对齐方式
                    fn = e.Font;
                    string s = this.Items[e.Index].ToString ();
                    StringFormat sf = new StringFormat();
                    sf.Alignment = StringAlignment.Near;
                    //根据不同的状态用不同的颜色表示
                    if (e.State == (DrawItemState.NoAccelerator | DrawItemState.NoFocusRect))
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.Red), r);
                        e.Graphics.DrawString(s, fn, new SolidBrush(Color.Black), r, sf);
                        e.DrawFocusRectangle();
                    }
                    else
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.White), r);
                        e.Graphics.DrawString(s, fn, new SolidBrush(Shared.FontColor), r, sf);
                        e.DrawFocusRectangle();
                    }
                }
                else
                {
                    fn = e.Font;
                    StringFormat sf = new StringFormat();
                    sf.Alignment = StringAlignment.Near;
                    string s = this.Items[e.Index].ToString ();
                    e.Graphics.FillRectangle(new SolidBrush(Shared.ControlBackColor), r);
                    e.Graphics.DrawString(s, fn, new SolidBrush(Shared.FontColor), r, sf);
                    
                }
            }
        }

        private bool _mouseEnter = false;

        protected override void OnMouseEnter(EventArgs e)
        {
            _mouseEnter = true;

            IntPtr hDC = IntPtr.Zero;
            Graphics gdc = null;
            hDC = Win32.GetWindowDC(this.Handle);
            gdc = Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.MouseMoveDrawButton, new Rectangle(this.Width - 20, 3, 16, 16));

            Win32.ReleaseDC(this.Handle, hDC);
            gdc.Dispose();

            base.OnMouseEnter(e);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            _mouseEnter = false;
            IntPtr hDC = IntPtr.Zero;
            Graphics gdc = null;
            hDC = Win32.GetWindowDC(this.Handle);
            gdc = Graphics.FromHdc(hDC);

            gdc.DrawImage(Shared.NomalDrawButton, new Rectangle(this.Width - 20, 3, 16, 16));

            Win32.ReleaseDC(this.Handle, hDC);
            base.OnMouseLeave(e);
        }

        public Image MouseMoveImage
        {
            get
            {
                return _mouseMoveImage;
            }
            set
            {
                _mouseMoveImage = value;
            }
        }

        public Image MouseDownImage
        {
            get
            {
                return _mouseDownImage;
            }
            set
            {
                _mouseDownImage = value;
            }
        }
        public Image NormalImage
        {
            get
            {
                return _normalImage;
            }
            set
            {
                _normalImage = value;
            }
        }
        public void ResetBitmap()
        {
            this.NormalImage = Shared.NomalDrawButton;
            this.MouseDownImage = Shared.MouseDownDrawButton;
            this.MouseMoveImage = Shared.MouseMoveDrawButton;
        }
    }
}[/code]

本帖被以下淘专辑推荐:

  • · 皮肤|主题: 15, 订阅: 0
发表于 2015-5-6 15:54:42 | 显示全部楼层
找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里联系我
感谢您的无私奉献,真是帮了我的大忙了
发表于 2015-6-8 18:00:00 | 显示全部楼层
找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里联系我
强烈支持楼主ing……
您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备17001017号-1)

GMT+8, 2021-9-28 12:09

© 2014-2021

快速回复 返回顶部 返回列表