zoukankan      html  css  js  c++  java
  • 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 OnMouseMove(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                 else
    112                 {
    113                     mouseItem.IsFocus = false;
    114                     this.Cursor = Cursors.Arrow;
    115                 }
    116 
    117                 this.Invalidate();
    118                 break;
    119             }
    120         }
    121     }
    122 
    123     protected override void OnMouseClick(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 OnMouseLeave(EventArgs e)
    137     {
    138         base.OnMouseLeave(e);
    139         this.mouseItem = null;
    140         this.Invalidate();
    141     }
    142 }
  • 相关阅读:
    NodeJs搭建简单的Http和Https服务器
    VSCode C++开发环境配置
    OpenCV查找并发现轮廓
    OpenCV使用连通组件检测并输出图像中的对象
    OpenCV使用阈值截断实现二值分割(黑白图)
    使用OpenCV实现背景减除
    get current UTC datetime of Python
    setTimeout and setInterval counterpart of Python
    setup airflow on MySQL
    HeidiSQL
  • 原文地址:https://www.cnblogs.com/yuefei/p/4062998.html
Copyright © 2011-2022 走看看