欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

(四十三)c#Winform自定义控件-Listview

程序员文章站 2023-11-06 10:43:10
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。 GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:https://gitee.com/kwwwvagaa/net_winform_custom_contr ......

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

github:https://github.com/kwwwvagaa/netwinformcontrol

码云:

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 

麻烦博客下方点个【推荐】,谢谢

nuget

install-package hzh_controls

目录

用处及效果

使用分页控件效果

(四十三)c#Winform自定义控件-Listview

不使用分页控件效果

(四十三)c#Winform自定义控件-Listview

准备工作

我们需要元素控件,需要列表控件,另外为了具有更好的扩展性,元素控件实现接口,方便进行扩展

我们用到了分页控件,如果你还不了解,请移步查看

(十二)c#winform自定义控件-分页控件

我们这里的元素控件用到圆角,故继承基类控件uccontrolbase,如果不了解,请移步查看

(一)c#winform自定义控件-基类控件

开始

添加一个接口,用来约束元素控件

 1  public interface ilistviewitem
 2     {
 3         /// <summary>
 4         /// 数据源
 5         /// </summary>
 6         object datasource { get; set; }
 7         /// <summary>
 8         /// 选中项事件
 9         /// </summary>
10         event eventhandler selecteditemevent;
11         /// <summary>
12         /// 选中处理,一般用以更改选中效果
13         /// </summary>
14         /// <param name="blnselected">是否选中</param>
15         void setselected(bool blnselected);
16     }

添加一个元素控件,命名uclistviewitem,我们这里继承基类控件uccontrolbase,实现接口ilistviewitem

 1 using system;
 2 using system.collections.generic;
 3 using system.componentmodel;
 4 using system.drawing;
 5 using system.data;
 6 using system.linq;
 7 using system.text;
 8 using system.windows.forms;
 9 
10 namespace hzh_controls.controls
11 {
12     [toolboxitem(false)]
13     public partial class uclistviewitem : uccontrolbase, ilistviewitem
14     {
15         private object m_datasource;
16         public object datasource
17         {
18             get
19             {
20                 return m_datasource;
21             }
22             set
23             {
24                 m_datasource = value;
25                 lbltitle.text = value.tostring();
26             }
27         }
28 
29         public event eventhandler selecteditemevent;
30         public uclistviewitem()
31         {
32             initializecomponent();
33             lbltitle.mousedown += lbltitle_mousedown;
34         }
35 
36         void lbltitle_mousedown(object sender, mouseeventargs e)
37         {
38             if (selecteditemevent != null)
39             {
40                 selecteditemevent(this, e);
41             }
42         }
43 
44         public void setselected(bool blnselected)
45         {
46             if (blnselected)
47                 this.fillcolor = color.fromargb(255, 247, 245);
48             else
49                 this.fillcolor = color.white;
50             this.refresh();
51         }
52     }
53 }
 1 namespace hzh_controls.controls
 2 {
 3     partial class uclistviewitem
 4     {
 5         /// <summary> 
 6         /// 必需的设计器变量。
 7         /// </summary>
 8         private system.componentmodel.icontainer components = null;
 9 
10         /// <summary> 
11         /// 清理所有正在使用的资源。
12         /// </summary>
13         /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
14         protected override void dispose(bool disposing)
15         {
16             if (disposing && (components != null))
17             {
18                 components.dispose();
19             }
20             base.dispose(disposing);
21         }
22 
23         #region 组件设计器生成的代码
24 
25         /// <summary> 
26         /// 设计器支持所需的方法 - 不要
27         /// 使用代码编辑器修改此方法的内容。
28         /// </summary>
29         private void initializecomponent()
30         {
31             this.lbltitle = new system.windows.forms.label();
32             this.suspendlayout();
33             // 
34             // lbltitle
35             // 
36             this.lbltitle.dock = system.windows.forms.dockstyle.fill;
37             this.lbltitle.location = new system.drawing.point(0, 0);
38             this.lbltitle.name = "lbltitle";
39             this.lbltitle.size = new system.drawing.size(107, 96);
40             this.lbltitle.tabindex = 0;
41             this.lbltitle.textalign = system.drawing.contentalignment.middlecenter;
42             // 
43             // uclistviewitem
44             // 
45             this.autoscalemode = system.windows.forms.autoscalemode.none;
46             this.backcolor = system.drawing.color.transparent;
47             this.controls.add(this.lbltitle);
48             this.fillcolor = system.drawing.color.white;
49             this.isradius = true;
50             this.isshowrect = true;
51             this.name = "uclistviewitem";
52             this.rectcolor = system.drawing.color.fromargb(((int)(((byte)(232)))), ((int)(((byte)(232)))), ((int)(((byte)(232)))));
53             this.size = new system.drawing.size(107, 96);
54             this.resumelayout(false);
55 
56         }
57 
58         #endregion
59 
60         private system.windows.forms.label lbltitle;
61     }
62 }

然后需要一个列表来显示元素控件

添加一个用户控件,命名uclistview

一些属性

  1 int m_intcellwidth = 130;//单元格宽度
  2         int m_intcellheight = 120;//单元格高度
  3 
  4         private type m_itemtype = typeof(uclistviewitem);
  5 
  6         [description("单元格类型,如果无法满足您的需求,你可以自定义单元格控件,并实现接口ilistviewitem"), category("自定义")]
  7         public type itemtype
  8         {
  9             get { return m_itemtype; }
 10             set
 11             {
 12                 if (!typeof(ilistviewitem).isassignablefrom(value) || !value.issubclassof(typeof(control)))
 13                     throw new exception("单元格控件没有继承实现接口ilistviewitem");
 14                 m_itemtype = value;
 15             }
 16         }
 17 
 18         private ucpagercontrolbase m_page = null;
 19         /// <summary>
 20         /// 翻页控件
 21         /// </summary>
 22         [description("翻页控件,如果ucpagercontrol不满足你的需求,请自定义翻页控件并继承ucpagercontrolbase"), category("自定义")]
 23         public ucpagercontrolbase page
 24         {
 25             get { return m_page; }
 26             set
 27             {
 28                 m_page = value;
 29                 if (value != null)
 30                 {
 31                     if (!typeof(ipagecontrol).isassignablefrom(value.gettype()) || !value.gettype().issubclassof(typeof(ucpagercontrolbase)))
 32                         throw new exception("翻页控件没有继承ucpagercontrolbase");
 33                     this.panmain.autoscroll = false;
 34                     panpage.visible = true;
 35                     this.controls.setchildindex(panmain, 0);
 36                     m_page.showsourcechanged += m_page_showsourcechanged;
 37                     m_page.dock = dockstyle.fill;
 38                     this.panpage.controls.clear();
 39                     this.panpage.controls.add(m_page);
 40                     getcellcount();
 41                     this.datasource = m_page.getcurrentsource();
 42                 }
 43                 else
 44                 {
 45                     this.panmain.autoscroll = true;
 46                     m_page = null;
 47                     panpage.visible = false;
 48                 }
 49             }
 50         }
 51 
 52 
 53 
 54         private object m_datasource = null;
 55 
 56         [description("数据源,如果使用翻页控件,请使用翻页控件的datasource"), category("自定义")]
 57         public object datasource
 58         {
 59             get { return m_datasource; }
 60             set
 61             {
 62                 if (value == null)
 63                     return;
 64                 if (!typeof(ilist).isassignablefrom(value.gettype()))
 65                 {
 66                     throw new exception("数据源不是有效的数据类型,列表");
 67                 }
 68                 m_datasource = value;
 69                 reloadsource();
 70             }
 71         }
 72 
 73         int m_intcellcount = 0;//单元格总数
 74         [description("单元格总数"), category("自定义")]
 75         public int cellcount
 76         {
 77             get { return m_intcellcount; }
 78             private set
 79             {
 80                 m_intcellcount = value;
 81                 if (value > 0 && m_page != null)
 82                 {
 83                     m_page.pagesize = m_intcellcount;
 84                     m_page.reload();
 85                 }
 86             }
 87         }
 88 
 89         private list<object> m_selectedsource = new list<object>();
 90 
 91         [description("选中的数据"), category("自定义")]
 92         public list<object> selectedsource
 93         {
 94             get { return m_selectedsource; }
 95             set
 96             {
 97                 m_selectedsource = value;
 98                 reloadsource();
 99             }
100         }
101 
102         private bool m_ismultiple = true;
103 
104         [description("是否多选"), category("自定义")]
105         public bool ismultiple
106         {
107             get { return m_ismultiple; }
108             set { m_ismultiple = value; }
109         }
110 
111         [description("选中项事件"), category("自定义")]
112         public event eventhandler selecteditemevent;
113         public delegate void reloadgridstyleeventhandle(int intcellcount);
114         /// <summary>
115         /// 样式改变事件
116         /// </summary>
117         [description("样式改变事件"), category("自定义")]
118         public event reloadgridstyleeventhandle reloadgridstyleevent;

一下辅助函数

  1 #region 重新加载数据源
  2         /// <summary>
  3         /// 功能描述:重新加载数据源
  4         /// 作  者:hzh
  5         /// 创建日期:2019-06-27 16:47:32
  6         /// 任务编号:pos
  7         /// </summary>
  8         public void reloadsource()
  9         {
 10             controlhelper.freezecontrol(this, true);
 11             if (this.panmain.controls.count <= 0)
 12             {
 13                 reloadgridstyle();
 14             }
 15             if (m_datasource == null || ((ilist)m_datasource).count <= 0)
 16             {
 17                 for (int i = this.panmain.controls.count - 1; i >= 0; i--)
 18                 {
 19                     this.panmain.controls[i].visible = false;
 20                 }
 21 
 22                 return;
 23             }
 24             int intcount = math.min(((ilist)m_datasource).count, this.panmain.controls.count);
 25 
 26             for (int i = 0; i < intcount; i++)
 27             {
 28                 ((ilistviewitem)this.panmain.controls[i]).datasource = ((ilist)m_datasource)[i];
 29                 if (m_selectedsource.contains(((ilist)m_datasource)[i]))
 30                 {
 31                     ((ilistviewitem)this.panmain.controls[i]).setselected(true);
 32                 }
 33                 else
 34                 {
 35                     ((ilistviewitem)this.panmain.controls[i]).setselected(false);
 36                 }
 37                 this.panmain.controls[i].visible = true;
 38             }
 39 
 40             for (int i = this.panmain.controls.count - 1; i >= intcount; i--)
 41             {
 42                 if (this.panmain.controls[i].visible)
 43                     this.panmain.controls[i].visible = false;
 44             }
 45             controlhelper.freezecontrol(this, false);
 46         }
 47         #endregion
 48 
 49         #region 刷新表格
 50         /// <summary>
 51         /// 功能描述:刷新表格样式
 52         /// 作  者:hzh
 53         /// 创建日期:2019-06-27 16:35:25
 54         /// 任务编号:pos
 55         /// </summary>
 56         public void reloadgridstyle()
 57         {
 58             form frmmain = this.findform();
 59             if (frmmain != null && !frmmain.isdisposed && frmmain.visible && this.visible)
 60             {
 61                 getcellcount();
 62                 try
 63                 {
 64                     controlhelper.freezecontrol(this, true);
 65                     if (this.panmain.controls.count < m_intcellcount)
 66                     {
 67                         int intcontrolscount = this.panmain.controls.count;
 68                         for (int i = 0; i < m_intcellcount - intcontrolscount; i++)
 69                         {
 70                             control uc = (control)activator.createinstance(m_itemtype);
 71                             uc.margin = new system.windows.forms.padding(5, 5, 5, 5);
 72 
 73                             (uc as ilistviewitem).selecteditemevent += uclistview_selecteditemevent;
 74                             uc.visible = false;
 75                             this.panmain.controls.add(uc);
 76                         }
 77                     }
 78                     else if (this.panmain.controls.count > m_intcellcount)
 79                     {
 80                         int intcontrolscount = this.panmain.controls.count;
 81                         for (int i = intcontrolscount - 1; i > m_intcellcount - 1; i--)
 82                         {
 83                             this.panmain.controls.removeat(i);
 84                         }
 85                     }
 86                     foreach (control item in this.panmain.controls)
 87                     {
 88                         item.size = new size(m_intcellwidth, m_intcellheight);
 89                     }
 90                 }
 91                 finally
 92                 {
 93                     controlhelper.freezecontrol(this, false);
 94                 }
 95                 if (reloadgridstyleevent != null)
 96                 {
 97                     reloadgridstyleevent(m_intcellcount);
 98                 }
 99             }
100 
101         }
102 
103         void uclistview_selecteditemevent(object sender, eventargs e)
104         {
105             var selecteditem = sender as ilistviewitem;
106 
107             if (m_selectedsource.contains(selecteditem.datasource))
108             {
109                 m_selectedsource.remove(selecteditem.datasource);
110                 selecteditem.setselected(false);
111             }
112             else
113             {
114                 if (m_ismultiple)
115                 {
116                     m_selectedsource.add(selecteditem.datasource);
117                     selecteditem.setselected(true);
118                 }
119                 else
120                 {
121                     if (m_selectedsource.count > 0)
122                     {
123                         int intcount = math.min(((ilist)m_datasource).count, this.panmain.controls.count);
124                         for (int i = 0; i < intcount; i++)
125                         {
126                             var item = ((ilistviewitem)this.panmain.controls[i]);
127                             if (m_selectedsource.contains(item.datasource))
128                             {
129                                 item.setselected(false);
130                                 break;
131                             }
132                         }
133                     }
134 
135                     m_selectedsource = new list<object>() { selecteditem.datasource };
136                     selecteditem.setselected(true);
137 
138                 }
139             }
140 
141             if (selecteditemevent != null)
142             {
143                 selecteditemevent(sender, e);
144             }
145         }
146         #endregion
147 
148         #region 获取cell总数
149         /// <summary>
150         /// 功能描述:获取cell总数
151         /// 作  者:hzh
152         /// 创建日期:2019-06-27 16:28:58
153         /// 任务编号:pos
154         /// </summary>
155         private void getcellcount()
156         {
157             if (this.panmain.width == 0)
158                 return;
159             control item = (control)activator.createinstance(m_itemtype);
160 
161 
162             int intxcount = (this.panmain.width - 10) / (item.width + 10);
163             m_intcellwidth = item.width + ((this.panmain.width - 10) % (item.width + 10)) / intxcount;
164 
165             int intycount = (this.panmain.height - 10) / (item.height + 10);
166             m_intcellheight = item.height + ((this.panmain.height - 10) % (item.height + 10)) / intycount;
167             int intcount = intxcount * intycount;
168 
169             if (page == null)
170             {
171                 if (((ilist)m_datasource).count > intcount)
172                 {
173                     intxcount = (this.panmain.width - 10 - 20) / (item.width + 10);
174                     m_intcellwidth = item.width + ((this.panmain.width - 10 - 20) % (item.width + 10)) / intxcount;
175                 }
176                 intcount = math.max(intcount, ((ilist)m_datasource).count);
177             }
178 
179             cellcount = intcount;
180         }
181         #endregion

一些事件

    private void panmain_resize(object sender, eventargs e)
        {
            reloadgridstyle();
        }
void m_page_showsourcechanged(object currentsource)
        {
            this.datasource = currentsource;
        }

 

你会发现,有个itemtype属性,这个用来定义列表呈现那种子元素,这么用的好处就是,当你觉得我写的这个元素控件uclistviewitem并不能满足你需求的时候,你可以添加一个自定义控件,并实现接口ilistviewitem,然后将你自定义的控件指定给这个属性,列表就会呈现出来了,是不是很方便,列表会自动根据你的元素控件的大小来适量调整来填充到列表中的。

 

还有一个page属性,这个是用来表示用哪个分页控件,当然你也可以不用,我已经提供了2种分页控件,如果你觉得还是不满足你的话,去参考分页控件那个文章,自己添加一个分页控件吧。

最后的话

如果你喜欢的话,请到  点个星星吧