首页 > 代码库 > winform下重画ListBox

winform下重画ListBox

Windows Forms是由Win32 API封装的开发组件,最初是为了替代mfc,但却没有体现与Model View Controller架构对应的特色,进而在.net framework 3.0中推出了wpf,富控件数据显示方面,利用模板功能轻松实现。

在winform下要想自定义一些用户控件,就需要运用的2D绘画类。下图我们为ListBox重新排列了数据显示方式,并为每一个item加入了删除按钮。

1

首先我们设计一个承载数据的类ListBoxItem。

 1 public class ListBoxItem : IDisposable 2 { 3     public Guid Id { get; set; } 4  5     public string Name { get; set; } 6  7     public string IP { get; set; } 8  9     public string Mac { get; set; }10 11     [System.ComponentModel.DefaultValue(typeof(System.Drawing.Image), "null")]12     public System.Drawing.Image Image { get; set; }13 14     public bool IsFocus { get; set; }15 16     public ListBoxItem() { }17 18     public ListBoxItem(Guid id, string name, string ip, string mac, System.Drawing.Image image)19     {20         this.Id = id;21         this.Name = name;22         this.IP = ip;23         this.Mac = mac;24         this.Image = image;25         this.IsFocus = false;26     }27 28     public void Dispose()29     {30         this.Image = null;31     }32 }

然后我们再为ListBox写一个用于展现数据的数据源ListBoxItemCollection,这里实现了迭代和集合操作接口,可以根据需要扩展数据操作方法。

[System.ComponentModel.ListBindable(false)]public class ListBoxItemCollection : IList, ICollection, IEnumerable{    private UserListBox m_owner;    public ListBoxItemCollection(UserListBox owner)    {        this.m_owner = owner;    }    internal UserListBox Owner    {        get { return this.m_owner; }    }    #region  override    public ListBoxItem this[int index]    {        get { return Owner.OldItemSource[index] as ListBoxItem; }        set { Owner.OldItemSource[index] = value; }    }    public int Count    {        get { return Owner.OldItemSource.Count; }    }    public bool IsReadOnly    {        get { return Owner.OldItemSource.IsReadOnly; }    }    public int Add(ListBoxItem item)    {        if (item == null)        {            throw new ArgumentException("item is null");        }        return Owner.OldItemSource.Add(item);    }    public void AddRange(ListBoxItem[] items)    {        Owner.OldItemSource.AddRange(items);    }    public void Clear()    {        if (Owner.OldItemSource.Count > 0)        {            Owner.OldItemSource.Clear();        }    }    public bool Contains(ListBoxItem item)    {        bool rst = false;        foreach (ListBoxItem oldItem in Owner.OldItemSource)        {            if (oldItem.Id == item.Id)            {                rst = true;                break;            }        }        return rst;    }    public void CopyTo(ListBoxItem[] destination, int arrayIndex)    {        Owner.OldItemSource.CopyTo(destination, arrayIndex);    }    public int IndexOf(ListBoxItem item)    {        return Owner.OldItemSource.IndexOf(item);    }    public void Insert(int index, ListBoxItem item)    {        if (item == null)        {            throw new ArgumentException("item is null");        }        Owner.OldItemSource.Insert(index, item);    }    public void Remove(ListBoxItem item)    {        Owner.OldItemSource.Remove(item);    }    public void RemoveAt(int index)    {        Owner.OldItemSource.RemoveAt(index);    }    public IEnumerator GetEnumerator()    {        return Owner.OldItemSource.GetEnumerator();    }    int IList.Add(object value)    {        if (!(value is ListBoxItem))        {            throw new ArgumentException();        }        return Add(value as ListBoxItem);    }    void IList.Clear()    {        Clear();    }    bool IList.Contains(object value)    {        return Contains(value as ListBoxItem);    }    int IList.IndexOf(object value)    {        return IndexOf(value as ListBoxItem);    }    void IList.Insert(int index, object value)    {        if (!(value is ListBoxItem))        {            throw new ArgumentException();        }        Insert(index, value as ListBoxItem);    }    bool IList.IsFixedSize    {        get { return false; }    }    bool IList.IsReadOnly    {        get { return IsReadOnly; }    }    void IList.Remove(object value)    {        Remove(value as ListBoxItem);    }    void IList.RemoveAt(int index)    {        RemoveAt(index);    }    object IList.this[int index]    {        get { return this[index]; }        set        {            if (!(value is ListBoxItem))            {                throw new ArgumentException();            }            this[index] = value as ListBoxItem;        }    }    void ICollection.CopyTo(Array array, int index)    {        CopyTo((ListBoxItem[])array, index);    }    int ICollection.Count    {        get { return Count; }    }    bool ICollection.IsSynchronized    {        get { return false; }    }    object ICollection.SyncRoot    {        get { return false; }    }    IEnumerator IEnumerable.GetEnumerator()    {        return GetEnumerator();    }    #endregion    #region  extention    public ListBoxItem FindByMac(string mac)    {        foreach (ListBoxItem item in Owner.OldItemSource)        {            if (item.Mac == mac)            {                return item;            }        }        return null;    }    #endregion}

下面可以为工程new一个新项——自定义控件,命名为UserListBox。

这里有几个地方要说明一下,首先在默认构造函数里面的参数:

DrawMode.OwnerDrawVariable启用控件重绘功能。

DoubleBuffer开启后避免复杂绘画造成窗体闪烁,这个缓冲的原理是将绘画操作放在内存里操作,完成后才会复制到图形界面上,进而避免的闪烁。

OnPaint进行了重写,这个方法是根据pc屏幕分辨率刷新频率来执行的,会不断的重复执行,进而持久化图形界面。

Invalidate方法,会立即刷新UI。

Item上的按钮事件,是通过ListBox的click事件,取到鼠标的在界面上的定位,调用相对应的方法。

  1 public partial class UserListBox : ListBox  2 {  3     public ListBoxItem mouseItem;  4     private ListBoxItemCollection m_Items;  5   6     public UserListBox() : base()  7     {  8         InitializeComponent();  9  10         m_Items = new ListBoxItemCollection(this); 11  12         base.DrawMode = DrawMode.OwnerDrawVariable; 13         this.SetStyle(ControlStyles.UserPaint, true); 14         this.SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲 15         this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); // 双缓冲    16         this.SetStyle(ControlStyles.ResizeRedraw, true); // 调整大小时重绘 17         this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.  18         this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); // 开启控件透明 19     } 20  21     public new ListBoxItemCollection Items 22     { 23         get { return m_Items; } 24     } 25  26     internal ListBox.ObjectCollection OldItemSource 27     { 28         get { return base.Items; } 29     } 30  31     protected override void OnPaint(PaintEventArgs e) 32     { 33         Graphics g = e.Graphics; 34          35         // you can set SeletedItem background 36         if (this.Focused && this.SelectedItem != null) 37         { 38         } 39  40         for (int i = 0; i < Items.Count; i++) 41         { 42             Rectangle bounds = this.GetItemRectangle(i); 43  44             if (mouseItem == Items[i]) 45             { 46                 Color leftColor = Color.FromArgb(200, 192, 224, 248); 47                 using (SolidBrush brush = new SolidBrush(leftColor)) 48                 { 49                     g.FillRectangle(brush, new Rectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height)); 50                 } 51  52                 Color rightColor = Color.FromArgb(252, 233, 161); 53                 using (SolidBrush brush = new SolidBrush(rightColor)) 54                 { 55                     g.FillRectangle(brush, new Rectangle(bounds.Width - 40, bounds.Y, 40, bounds.Height)); 56                 } 57             } 58  59             int fontLeft = bounds.Left + 40 + 15; 60             System.Drawing.Font font = new System.Drawing.Font("微软雅黑", 9); 61             g.DrawString(Items[i].Name, font, new SolidBrush(this.ForeColor), fontLeft, bounds.Top + 5); 62             g.DrawString(Items[i].IP, font, new SolidBrush(Color.FromArgb(128, 128, 128)), fontLeft, bounds.Top + 20); 63             g.DrawString(Items[i].Mac, font, new SolidBrush(Color.FromArgb(128, 128, 128)), fontLeft, bounds.Top + 35); 64  65             if (Items[i].Image != null) 66             { 67                 g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear; 68                 g.DrawImage(Items[i].Image, new Rectangle(bounds.X + 5, (bounds.Height - 40) / 2 + bounds.Top, 40, 40)); 69             } 70             g.DrawImage(Properties.Resources.error, new Rectangle(bounds.Width - 28, (bounds.Height - 16) / 2 + bounds.Top, 16, 16)); 71         } 72         base.OnPaint(e); 73     } 74  75     protected override void OnMeasureItem(MeasureItemEventArgs e) 76     { 77         base.OnMeasureItem(e); 78         if (Items.Count > 0) 79         { 80             ListBoxItem item = Items[e.Index]; 81             e.ItemHeight = 54; 82         } 83          84     } 85  86     protected override void OnSelectedIndexChanged(EventArgs e) 87     { 88         base.OnSelectedIndexChanged(e); 89     } 90  91     protected override void onm ouseMove(MouseEventArgs e) 92     { 93         base.OnMouseMove(e); 94         for (int i = 0; i < Items.Count; i++) 95         { 96             Rectangle bounds = this.GetItemRectangle(i); 97             Rectangle deleteBounds = new Rectangle(bounds.Width - 28, (bounds.Height - 16) / 2 + bounds.Top, 16, 16); 98  99             if (bounds.Contains(e.X, e.Y))100             {101                 if (Items[i] != mouseItem)102                 {103                     mouseItem = Items[i];104                 }105 106                 if (deleteBounds.Contains(e.X, e.Y))107                 {108                     mouseItem.IsFocus = true;109                     this.Cursor = Cursors.Hand;110                 }111                 else112                 {113                     mouseItem.IsFocus = false;114                     this.Cursor = Cursors.Arrow;115                 }116 117                 this.Invalidate();118                 break;119             }120         }121     }122 123     protected override void onm ouseClick(MouseEventArgs e)124     {125         base.OnMouseClick(e);126         if (mouseItem.IsFocus)127         {128             ListBoxItem deleteItem = mouseItem;129             if(MessageBox.Show("confirm to delete", "", MessageBoxButtons.OKCancel) == DialogResult.OK)130             {131                 this.Items.Remove(deleteItem);132             }133         }134     }135 136     protected override void onm ouseLeave(EventArgs e)137     {138         base.OnMouseLeave(e);139         this.mouseItem = null;140         this.Invalidate();141     }142 }

 

winform下重画ListBox