http://www.hzhcontrols.comhtml
入行已經7,8年了,一直想作一套漂亮點的自定義控件,因而就有了本系列文章。git
GitHub:https://github.com/kwwwvagaa/NetWinformControlgithub
碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_control.gitc#
若是以爲寫的還行,請點個 star 支持一下吧編輯器
麻煩博客下方點個【推薦】,謝謝函數
Install-Package HZH_Controls
http://www.javashuo.com/article/p-hacmmtru-mw.htmlpost
使用分頁控件效果this
不使用分頁控件效果spa
咱們須要元素控件,須要列表控件,另外爲了具備更好的擴展性,元素控件實現接口,方便進行擴展
咱們用到了分頁控件,若是你還不瞭解,請移步查看
咱們這裏的元素控件用到圓角,故繼承基類控件UCControlBase,若是不瞭解,請移步查看
添加一個接口,用來約束元素控件
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種分頁控件,若是你以爲仍是不知足你的話,去參考分頁控件那個文章,本身添加一個分頁控件吧。
若是你喜歡的話,請到 https://gitee.com/kwwwvagaa/net_winform_custom_control 點個星星吧