C#控件美化之路(9):c# description_美化控件ListBox

5371a0930f8833bb46bfe1afbb2343f0.png

01cfb8e15cdda59e92109b5a85c1e010.png

ef7ddb57144e5e3dda5e16d60129c69b.gif

ListBox 在C# winform编程中,使用的比较多,用途也很广,今天带大家一步步的美化ListBox控件。

本文主要实现。

1.奇数行与偶数行颜色交替。

2.选中行颜色。

3.鼠标移动停留行颜色。

4.增加序号

5.增加单选框显示。

前面的若干文章,已经讲解了重绘等一些技巧,这篇文章,理解内容相对比较多,看的小伙伴可以收藏,若碰到问题,欢迎在下方留言。

重绘第一步依然

新建一个类 ,继承ListBox

a4126c5d340e9f23951fe139052eaa63.png

文中写的部分在之前文章提到过,本文不做详细描述,主要就是减少闪烁,双缓存等。

构造函数中内容

public class WenListBox : ListBox
{
        public WenListBox()  
        {
            base.SetStyle(
                //ControlStyles.UserPaint |
                ControlStyles.DoubleBuffer |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.ResizeRedraw |
                ControlStyles.SupportsTransparentBackColor, true);
            base.UpdateStyles();
            this.DrawMode = DrawMode.OwnerDrawFixed;
            this.IntegralHeight = false;        
        }
}

ControlStyles.UserPaint 此项是所有内容都由用户绘制,一般不用为true。若是需要全部用户自定义绘制。高级重绘,应当此项勾选,本文主要是绘制项,就不把此项设置为true。

私有属性

        #region 私有属性
        //选中项改变之前的选中项索引
        private int selectBefore = -1;
        private int MouseItemIndex;
        private bool line = true;
        private bool radioBox = true;
        private Color oneRowColor = Color.DeepSkyBlue;
        private Color towRowColor = Color.Aquamarine;
        private Color selectedRowColor = Color.DarkCyan;
        private Color mouseMoveRowColor = Color.Cyan; 
        private int itemHeight=20;
        #endregion

公有属性

        #region 公有属性   
        [Category("Wen"), Description("是否增加序号"), DefaultValue(true)]
        public bool Line { get => line; set { line = value; this.Invalidate(); } } 
        [Category("Wen"), Description("是否增加选框"), DefaultValue(true)] 
        public bool RadioBox { get => radioBox; set { radioBox = value; this.Invalidate(); } }   
        [Category("Wen"), Description("奇数行颜色"), DefaultValue(typeof(Color), "DeepSkyBlue")]  
        public Color OneRowColor { get => oneRowColor; set { oneRowColor = value; this.Invalidate(); } } 
        [Category("Wen"), Description("偶数行颜色"), DefaultValue(typeof(Color), "Aquamarine")]  
        public Color TowRowColor { get => towRowColor; set { towRowColor = value; this.Invalidate(); } }
        [Category("Wen"), Description("选中颜色"), DefaultValue(typeof(Color), "DarkCyan")]
        public Color SelectedRowColor { get => selectedRowColor; set { selectedRowColor = value; this.Invalidate(); } }   
        [Category("Wen"), Description("鼠标移动行颜色"), DefaultValue(typeof(Color), "Cyan")]   
        public Color MouseMoveRowColor { get => mouseMoveRowColor; set { mouseMoveRowColor = value; this.Invalidate(); } }  
        #endregion

每一项都有详细备注描述,就不多做解释。若有不明白欢迎在文中评论留言转发。

部分属性重写,主要目的是按照自定义修改。重置属性或者重写属性

        #region 重置属性或者重写属性     
        [Category("Wen"), Description("设置单项高度"), DefaultValue(20)] 
        public new int ItemHeight { get => itemHeight; set { base.ItemHeight = value; itemHeight = value; } }     
        #endregion

此处贴一个常用方法颜色获取Brush,当然此方法一般可以直接写在代码中没必要专门用一个方法,本文主要便于理解,一般在编程中,都会用using。本文不演示,后续文章转成解释using的使用。

        #region 颜色获取Brush 
        private Brush GetBrush(string b)  
        {
            return new SolidBrush(ColorTranslator.FromHtml(b));      
        }      
        private Brush GetBrush(Color c)        
        {          
            return new SolidBrush(c);     
        }     
        #endregion

执行重绘必要因素

ListBox 由于目前重绘只重绘项,不直接全部重绘,所以只需要重写OnDrawItem

贴代码块

        //重绘指定项 
        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            //base.OnDrawItem(e);  
            if (Items.Count == 0 || e.Index < 0) 
                return;
            Graphics g = e.Graphics; 
            Rectangle rec = GetItemRectangle(e.Index);
            if (GetSelected(e.Index)) 
            {
                rec.Inflate(0, -2); 
                ItemDraw(e.Index, g, rec, SelectedRowColor, e); 
            }         
            else if (e.Index == MouseItemIndex)   
            {
                ItemDraw(e.Index, g, rec, MouseMoveRowColor, e);  
            }   
            else if (e.Index % 2 != 1)    
            {
                ItemDraw(e.Index, g, rec, OneRowColor, e);
            }
            else
            {
                ItemDraw(e.Index, g, rec, TowRowColor, e);
            } 
        }

ItemDraw由于重绘重绘可利用代码较多,本文主要用了一个方法来实现。

        //刷新指定项目  
        private void ItemDraw(int index, Graphics g, Rectangle rec, Color c, DrawItemEventArgs e)   
        {
            ControlHelper.SetGDIHigh(g);
            g.FillRectangle(GetBrush(c), rec);
            Brush brush = GetBrush(e.ForeColor); 
            int radioWidth = 0;  
            if (RadioBox)
            {
                radioWidth = 20;
                Pen pen = new Pen(Color.Gray, 3);
                g.DrawEllipse(new Pen(brush) { Width=2}, new Rectangle(rec.X, (ItemHeight - 15) / 2 + rec.Y, 15, 15));    
                if (GetSelected(index))            
                    g.FillEllipse(brush, new Rectangle(rec.X + 5, (ItemHeight - 5) / 2 + rec.Y, 5, 5));   
            }       
            //绘制文字    
            if (Line)        
            {             
                Rectangle recLine = new Rectangle(rec.X + radioWidth, rec.Y, 50 - radioWidth, this.ItemHeight);       
                Rectangle recText = new Rectangle(rec.X + 50, rec.Y, rec.Width - 50, this.ItemHeight);         
                g.DrawString((index + 1).ToString(), Font, brush, recLine, ControlHelper.StringConters);      
                g.DrawString(Items[index]?.ToString(), Font, brush, recText, ControlHelper.StringConters);   
            }       
            else   
            {          
                Rectangle recText = new Rectangle(rec.X + radioWidth, rec.Y, rec.Width - radioWidth, this.ItemHeight);  
                g.DrawString(Items[index]?.ToString(), Font, brush, recText, ControlHelper.StringConters);   
            }    
        }

接下来 解决鼠标移动项目颜色改变

        //鼠标移动 
        protected override void OnMouseMove(MouseEventArgs e)       
        {    
            base.OnMouseMove(e); 
            int index = IndexFromPoint(e.Location);
            if (index < 0) return;       
            if (MouseItemIndex != index)    
            {           
                int indexBefore = MouseItemIndex;      
                MouseItemIndex = index;        
                this.RefreshItem(index);         
                this.RefreshItem(indexBefore);     
            }      
        }

鼠标离开指定项

        //鼠标移开事件    
        protected override void OnMouseLeave(EventArgs e)    
        {        
            base.OnMouseLeave(e);
            int index = MouseItemIndex;  
            MouseItemIndex = -1;       
            RefreshItem(index);   
        }

选中索引变化

        //选中索引变化    
        protected override void OnSelectedIndexChanged(EventArgs e)
        {          
            base.OnSelectedIndexChanged(e);   
            if (selectBefore != -1)      
            {            
                RefreshItem(selectBefore);    
            }          
            selectBefore = SelectedIndex;   
            object item = this.SelectedItem; 
            ItemClick?.Invoke(this, new WenListBoxEventArgs(item));  
        }

刷新指定索引项

        //刷新指定索引项    
        protected override void RefreshItem(int index)    
        {       
            if (index < 0 || Items.Count == 0)        
                return;         
            Graphics g = CreateGraphics();      
            Rectangle rec = GetItemRectangle(index);   
            g.SetClip(new Rectangle(rec.X, rec.Y+1, rec.Width, rec.Height-1));  
            if (SelectedIndex == index)         
                OnDrawItem(new DrawItemEventArgs(g, Font, rec, index, DrawItemState.Selected, Color.White, this.SelectedRowColor));   
            else              
                OnDrawItem(new DrawItemEventArgs(g, Font, rec, index, DrawItemState.None, this.ForeColor, this.SelectedRowColor));    
        }

到目前为止重绘已经完成,当然在常用中一般还需要增加项点击事件,可以按照需求自写一个委托事件。

写一个委托事件。 贴完整代码块

        public delegate void WenListBoxEventHandler(object sender, WenListBoxEventArgs e);
        public class WenListBoxEventArgs : EventArgs { public WenListBoxEventArgs(object item) { this.Item = item; } public object Item { get; set; } }

委托 项被点击事件

        #region 委托事件 
        [Category("Wen"), Description("项被点击事件")] 
        public event WenListBoxEventHandler ItemClick;  
        #endregion

至此一个完整listbox重绘已经完成。

c61dacc99b9cfd8d11f5a6fba48e49e6.png

a0dfc10d56a70ebb4cb83714007eed6b.gif

至此一个ListBox重绘完成。

关注文林软控。带你用C# 美化.NET控件。

猜你喜欢

转载自blog.csdn.net/lihongmao5911/article/details/115417145