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 }

 

你可能感兴趣的:(WinForm)