前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
官网:https://www.hzhcontrols.cn
GitHub:https://github.com/kwwwvagaa/NetWinformControl
如果觉得写的还行,请点个 star 支持一下吧
目录
c#Winform自定义控件-目录_c#winform自定义控件-有图标的按钮-CSDN博客
准备工作
当一个列表加载数据过多时,比如datagridview,如果数据过多,则可能超出内存,相应慢等问题,此时需要用到翻页控件。
设计思路,对翻页控件定义接口,基类实现,如果所列的翻页控件样式或功能无法满足你的需求的话,你只需要基类翻页控件基类或者实现接口即可。
定义接口是因为后面的一些列表控件内置了翻页控件,为了达到兼容扩展,所有使用了接口定义约束。
开始
首先需要一个分页事件用到的委托,偷懒,只写了一个
[Serializable]
[ComVisible(true)]
public delegate void PageControlEventHandler(object currentSource);
我们先定义一个接口IPageControl
1 public interface IPageControl
2 {
3 /// <summary>
4 /// 数据源改变时发生
5 /// </summary>
6 event PageControlEventHandler ShowSourceChanged;
7 /// <summary>
8 /// 数据源
9 /// </summary>
10 List<object> DataSource { get; set; }
11 /// <summary>
12 /// 显示数量
13 /// </summary>
14 int PageSize { get; set; }
15 /// <summary>
16 /// 开始下标
17 /// </summary>
18 int StartIndex { get; set; }
19 /// <summary>
20 /// 第一页
21 /// </summary>
22 void FirstPage();
23 /// <summary>
24 /// 前一页
25 /// </summary>
26 void PreviousPage();
27 /// <summary>
28 /// 下一页
29 /// </summary>
30 void NextPage();
31 /// <summary>
32 /// 最后一页
33 /// </summary>
34 void EndPage();
35 /// <summary>
36 /// 重新加载
37 /// </summary>
38 void Reload();
39 /// <summary>
40 /// 获取当前页数据
41 /// </summary>
42 /// <returns></returns>
43 List<object> GetCurrentSource();
44 /// <summary>
45 /// 总页数
46 /// </summary>
47 int PageCount { get; set; }
48 /// <summary>
49 /// 当前页
50 /// </summary>
51 int PageIndex { get; set; }
52 }
然后定义一个分页基类控件,添加一个用户控件,命名UCPagerControlBase,并实现接口IPageControl
看下属性
1 /// <summary>
2 /// 总页数
3 /// </summary>
4 public virtual int PageCount
5 {
6 get;
7 set;
8 }
9 private int m_pageIndex = 1;
10 /// <summary>
11 /// 当前页码
12 /// </summary>
13 public virtual int PageIndex
14 {
15 get { return m_pageIndex; }
16 set { m_pageIndex = value; }
17 }
18 /// <summary>
19 /// 关联的数据源
20 /// </summary>
21 public virtual List<object> DataSource { get; set; }
22 public virtual event PageControlEventHandler ShowSourceChanged;
23 private int m_pageSize = 1;
24 /// <summary>
25 /// 每页显示数量
26 /// </summary>
27 [Description("每页显示数量"), Category("自定义")]
28 public virtual int PageSize
29 {
30 get { return m_pageSize; }
31 set { m_pageSize = value; }
32 }
33 private int startIndex = 0;
34 /// <summary>
35 /// 开始的下标
36 /// </summary>
37 [Description("开始的下标"), Category("自定义")]
38 public virtual int StartIndex
39 {
40 get { return startIndex; }
41 set
42 {
43 startIndex = value;
44 if (startIndex <= 0)
45 startIndex = 0;
46 }
47 }
然后定义虚函数,并做一些默认实现
/// <summary>
/// 第一页
/// </summary>
public virtual void FirstPage()
{
if (DataSource == null)
return;
startIndex = 0;
var s = GetCurrentSource();
if (ShowSourceChanged != null)
{
ShowSourceChanged(s);
}
}
/// <summary>
/// 上一页
/// </summary>
public virtual void PreviousPage()
{
if (DataSource == null)
return;
if (startIndex == 0)
return;
startIndex -= m_pageSize;
if (startIndex < 0)
startIndex = 0;
var s = GetCurrentSource();
if (ShowSourceChanged != null)
{
ShowSourceChanged(s);
}
}
/// <summary>
/// 下一页
/// </summary>
public virtual void NextPage()
{
if (DataSource == null)
return;
if (startIndex + m_pageSize >= DataSource.Count)
{
return;
}
startIndex += m_pageSize;
if (startIndex < 0)
startIndex = 0;
var s = GetCurrentSource();
if (ShowSourceChanged != null)
{
ShowSourceChanged(s);
}
}
/// <summary>
/// 最后一页
/// </summary>
public virtual void EndPage()
{
if (DataSource == null)
return;
startIndex = DataSource.Count - m_pageSize;
if (startIndex < 0)
startIndex = 0;
var s = GetCurrentSource();
if (ShowSourceChanged != null)
{
ShowSourceChanged(s);
}
}
/// <summary>
/// 刷新数据
/// </summary>
public virtual void Reload()
{
var s = GetCurrentSource();
if (ShowSourceChanged != null)
{
ShowSourceChanged(s);
}
}
/// <summary>
/// 获取当前页数据
/// </summary>
/// <returns></returns>
public virtual List<object> GetCurrentSource()
{
if (DataSource == null)
return null;
int intShowCount = m_pageSize;
if (intShowCount + startIndex > DataSource.Count)
intShowCount = DataSource.Count - startIndex;
object[] objs = new object[intShowCount];
DataSource.CopyTo(startIndex, objs, 0, intShowCount);
var lst = objs.ToList();
bool blnLeft = false;
bool blnRight = false;
if (lst.Count > 0)
{
if (DataSource.IndexOf(lst[0]) > 0)
{
blnLeft = true;
}
else
{
blnLeft = false;
}
if (DataSource.IndexOf(lst[lst.Count - 1]) >= DataSource.Count - 1)
{
blnRight = false;
}
else
{
blnRight = true;
}
}
ShowBtn(blnLeft, blnRight);
return lst;
}
/// <summary>
/// 控制按钮显示
/// </summary>
/// <param name="blnLeftBtn">是否显示上一页,第一页</param>
/// <param name="blnRightBtn">是否显示下一页,最后一页</param>
protected virtual void ShowBtn(bool blnLeftBtn, bool blnRightBtn)
{ }
如此基类就完成了,看下完整代码
View Code
接下来就是具体的实现分页控件了,我们将实现2种不同样式的分页控件以适应不通的场景,
第一种
添加用户控件UCPagerControl,继承UCPagerControlBase
重新基类的部分函数
1 private void panel1_MouseDown(object sender, MouseEventArgs e)
2 {
3 PreviousPage();
4 }
5
6 private void panel2_MouseDown(object sender, MouseEventArgs e)
7 {
8 NextPage();
9 }
10
11 private void panel3_MouseDown(object sender, MouseEventArgs e)
12 {
13 FirstPage();
14 }
15
16 private void panel4_MouseDown(object sender, MouseEventArgs e)
17 {
18 EndPage();
19 }
20
21 protected override void ShowBtn(bool blnLeftBtn, bool blnRightBtn)
22 {
23 panel1.Visible = panel3.Visible = blnLeftBtn;
24 panel2.Visible = panel4.Visible = blnRightBtn;
25 }
完成,是不是很简单,看下全部代码
View Code
View Code
第二种
这种和第一种的唯一区别就是页面计算生成的部分了
添加一个用户控件UCPagerControl2,继承UCPagerControlBase
属性如下
1 public override event PageControlEventHandler ShowSourceChanged;
2
3 private List<object> m_dataSource;
4 public override List<object> DataSource
5 {
6 get
7 {
8 return m_dataSource;
9 }
10 set
11 {
12