winform下重画ListBox

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

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

首先我们设计一个承载数据的类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 }
时间: 2024-10-27 16:35:05

winform下重画ListBox的相关文章

Android组件Activity中的View绘画和动画(Animation)是否会重画?

Activity 就是Android中的活动,是Android系统中唯一一个可见组件. Activity中官网中有一句话: The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop() 这句话的意思是可以看见Activity的生命周期是从 调用onStart()方法开始 直到调用onStop()方法.这句话开始我就理解错误了.因为设置Ac

WinForm中重绘TabControl选项卡标题

最近开发WinForm频繁使用了TabControl控件,这个控件的选项卡没有BackgroundImage这个属性,那么如何为其各个选项卡添加背景图片呢?(这里说的是每个TabPage的头部,也就是标题,不是工作区域.) 最开始用到TabControl的时候,我的每个选项卡是写死的,而后由于项目需求又动态添加了TabControl并生成各个选项卡,而两次我都要重绘其标题,因此在这里把我当时两种情形下重绘的方法通过一个例子一起分享出来. 首先先在窗体拖个Tabcontrol控件,然后更改了其Al

winform下通过webclient使用非流方式上传(post)数据和文件

这两天因为工作的需要,需要做一个winform上传数据到服务器端的程序.当时第一个想法是通过webservice的方式来实现,后来觉得麻 烦,想偷懒就没有用这样的方式,http的post方式变成了第一选择.因为以前用的都是httpwebrequest之类的东西进行post提 交,winform下面还真的是第一次,不过很快就在网上找到了webclient这个类,接下来开始实现功能,话说webclient用起来还真的很简 单,一个头信息的声明,然后是URL,最后是post的数据,就完事了.正在高兴的

一个Winform下DataGridView控件外观的自定义类

一.关于起因 最近非常频繁的使用DataGridView控件,VS提供的Winform下DataGridView的默认样式非常难看.如果做美化处理的话,需要调整的地方非常多,且该控件的很多设置属性非常的晦涩,不是很人性化.每次进行设置都煞费脑筋,并且需要设置的DataGridView控件又比较多,如果手工一个一个调整非常麻烦.如果在每个窗体里逐个一行一行的用代码来设置,会造成代码很凌乱.琐碎,因此我对DataGridView格式设置的常用项封装到一个Helper类,通过这个帮助类可以一步到位完成

分享在winform下实现模块化插件编程

其实很早之前我就已经了解了在winform下实现插件编程,原理很简单,主要实现思路就是:先定一个插件接口作为插件样式及功能的约定,然后具体的插件就去实现这个插件接口,最后宿主(应用程序本身)就利用反射动态获取实现了插件接口的类型作为合法的插件,从而完成动态加载及宿主与插件之间的互动.因为之前一段时间一直搞B/S架构开发没有时间去实践,而恰好现在公司领导要求我对我公司原有的ERP系统架构进行重整,我们的ERP系统采用的基于分布式的三层架构,核心业务逻辑放在服务端,展示层与业务层之间采用基于WEB服

Linux下重命名文件或文件夹(mv命令与rename命令)

在Linux下重命名文件或目录,可以使用mv命令或rename命令 mv ------------ mv命令既可以重命名,又可以移动文件或文件夹. 例子:将目录A重命名为B mv A B 例子:将/a目录移动到/b下,并重命名为c mv /a /b/c 其实在文本模式中要重命名文件或目录,只需要使用mv命令就可以了,比如说要将一个名为abc的文件重命名为1234: mv abc 1234 注意,如果当前目录下也有个1234的文件的话,这个文件是会将它覆盖的. rename -----------

winform下 PictureBox 显示网络图片

Image pic = new Image.FromStream(WebRequest.Create("http://x.com/x.jpg").GetResponse().GetResponseStream()); picturebox1.Image = pic 对读取错误的处理没有加 winform下 PictureBox 显示网络图片,布布扣,bubuko.com

重画GoogleClusterTrace数据

由于项目计划书写作需要,重画了Qi Zhang, Mohamed Faten Zhani, Raouf Boutaba, Joseph L. Hellerstein, Dynamic Heterogeneity-Aware Resource Provisioning in the Cloud. IEEE TRANSACTIONS ON CLOUD COMPUTING, VOL. 2, NO. 1, JANUARY-MARCH 2014.中的TaskEvent分布统计图.原图更跟重画图如下: 原图

(转)winform下TCP通信的简单应用

本文转载自:http://blog.csdn.net/wanlong360599336/article/details/7557064 先看效果图: TCP比较繁琐的就是三次握手定理,每次再发送数据前都要先建立连接确认. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; us