VB.NET学习笔记:WinForm自定义DataGridView分页组合控件

测试环境:windows 7和Microsoft Visual Studio 2015

点击下载本文资源

VB.NET虽然提供了大量控件供我们使用,但很多控件仅提供最基础的功能。比如用DataGridView控件可以非常方便显示或操作数据库数据, 但却没有分页功能。本文介绍通过自定义窗体库组合VB.NET已有控件实现DataGridView控件分页显示功能。

测试效果如图:

DataGridView分页控件效果图
DataGridView控件分页功能效果图

这其实就是一个组合控件(CompositeControls),继承自UserControl类,将目前现有的控件根据需要组合到一起形成一个新的控件。具体做法如下:

一、新建Windows窗体控件库项目

如下图所示,名称按你喜欢的写上就行。Windows窗体控件库有可视化的设计视图,可以从工具箱添加VB.NET中已有的控件。

Windows窗体控件库

如果新建的是Windows窗体应用程序,也可以通过右键单击解决方案资源管理器中的项目名称,在弹出的右键菜单中点选“添加”-“新建项”,在弹出的“新建项目”窗口中选择“用户控件”,这个也是建自定义组合控件的,如下图所示。

和
标题

二、布局

在设计窗口里添加如下图所示的控件。

布局效果图

布局技巧分享:

1、按钮外观美化:如下图设置按钮的FlatAppearance的BorderSize为0,即去除边框,FlatStyle为Flat,即按钮外观为平面显示,通过Image属性为按钮添加图片。

按钮Button外观属性设置

2、TextBoxt和Lable设置:设置TextAlign可设置文本对齐方式,文本框和标签大小默认根据字号自动调整大小的,是不能通过Size属性来调整大小的,如果要调整Size属性,必须先把AutoSize属性设置为False。

3、控件对齐方式设置:大部分控件都可以通过设置Anchor属性来将控件绑定到容器的边缘,当组合控件大小整体改变时,里面的控件始终与绑定的边缘保持相同距离。

4、为控件设置鼠标划过文本提示:需要先从工具箱添加ToolTip控件,这时每个控件都多了一个ToolTip1上的ToolTip属性,在右侧设置的文本即为提示文本。

设置鼠标划过文本提示

三、编写分页控件代码

布局好后就可以编写分页代码了。包括分页控件的属性和事件。

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Public Class DataGridViewPaging
    Inherits UserControl
#Region "构造函数"
    Public Sub New()
        InitializeComponent()
    End Sub
#End Region

#Region "分页字段和属性"
    Private _pageIndex As Integer = 1
    ''' <summary>
    ''' 当前页面
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overridable Property PageIndex As Integer
        Get
            Return _pageIndex
        End Get
        Set(ByVal value As Integer)
            If value > 0 Then
                _pageIndex = value
            Else
                _pageIndex = 1
            End If
        End Set
    End Property

    Private _pageSize As Integer = 100
    ''' <summary>
    ''' 每页记录数(默认100)
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overridable Property PageSize As Integer
        Get
            Return _pageSize
        End Get
        Set(ByVal value As Integer)
            If value > 0 Then
                _pageSize = value
            Else
                _pageSize = 100
            End If
        End Set
    End Property

    Private _recordCount As Integer = 0
    ''' <summary>
    ''' 总记录数
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overridable Property RecordCount As Integer
        Get
            Return _recordCount
        End Get
        Set(ByVal value As Integer)
            If value >= 0 Then
                _recordCount = value
            Else
                _recordCount = 0
            End If
        End Set
    End Property

    Private _pageCount As Integer = 0
    ''' <summary>
    ''' 总页数
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property PageCount As Integer
        Get

            If _pageSize >= 0 Then
                _pageCount = GetPageCount()
            Else
                _pageCount = 0
            End If

            Return _pageCount
        End Get
    End Property

    ''' <summary>
    ''' 计算总页数
    ''' </summary>
    ''' <returns>总页数(Integer)</returns>
    ''' <remarks></remarks>
    Private Function GetPageCount() As Integer
        Dim pageCount As Integer = 0

        If RecordCount > 0 AndAlso PageSize > 0 Then
            If RecordCount Mod PageSize = 0 Then
                pageCount = CType(RecordCount / PageSize, Integer)
            Else
                pageCount = CType(RecordCount / PageSize, Integer) + 1
            End If
        End If

        Return pageCount
    End Function

    Private _CurrentPageFirstRecord As Integer = 0
    ''' <summary>
    ''' 当前页面首记录
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property CurrentPageFirstRecord As Integer
        Get
            If RecordCount > 0 Then
                If PageIndex = 1 OrElse PageCount = 1 Then '当前显示为第一页或只有一页
                    _CurrentPageFirstRecord = 1
                Else
                    _CurrentPageFirstRecord = (PageIndex - 1) * PageSize + 1
                End If
            End If
            Return _CurrentPageFirstRecord
        End Get
    End Property

    Private _CurrentPageLastRecord As Integer = 0
    ''' <summary>
    ''' 当前页面末记录
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property CurrentPageLastRecord As Integer
        Get
            If RecordCount > 0 Then
                If PageCount = 1 Then '只有一页
                    _CurrentPageLastRecord = RecordCount
                Else '有多页
                    If PageIndex = 1 Then '当前显示为第一页
                        _CurrentPageLastRecord = PageSize
                    ElseIf PageIndex = PageCount Then '当前显示为最后一页
                        _CurrentPageLastRecord = RecordCount
                    Else '中间页
                        _CurrentPageLastRecord = PageIndex * PageSize
                    End If
                End If
            End If
            Return _CurrentPageLastRecord
        End Get
    End Property

    Private _jumpText As String = "Go"
    ''' <summary>
    ''' 跳转按钮文本
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property JumpText As String
        Get

            If String.IsNullOrEmpty(_jumpText) Then
                _jumpText = "Go"
            End If

            Return _jumpText
        End Get
        Set(ByVal value As String)
            _jumpText = value
            BtnGo.Text = _jumpText
        End Set
    End Property
#End Region

#Region "页码变化触发事件"
    'Public Event OnPageChanged As EventHandler
    Public Delegate Sub EventPagingHandler(ByVal e As EventArgs)
    Public Event EventPaging As EventPagingHandler
#End Region

#Region "分页及相关事件功能实现"
    ''' <summary>
    ''' 外部调用
    ''' </summary>
    ''' <param name="count">总记录数</param>
    ''' <remarks></remarks>
    Public Sub DrawControl(ByVal count As Integer)
        RecordCount = count
        DrawControl(True)
    End Sub
    ''' <summary>
    ''' 页面控件呈现
    ''' </summary>
    ''' <param name="callEvent">是否触发事件,Ture则触发</param>
    ''' <remarks></remarks>
    Private Sub DrawControl(ByVal callEvent As Boolean)
        'BtnGo.Text = JumpText
        lblCurrentAndCountPage.Text = PageIndex.ToString() & "/" & PageCount.ToString()
        LblRecordRegionAndCount.Text = "当前记录:" & CurrentPageFirstRecord.ToString() &
            " - " & CurrentPageLastRecord.ToString() & " 总记录:" & RecordCount.ToString()
        txtPageSize.Text = PageSize.ToString()

        If callEvent Then
            'RaiseEvent OnPageChanged(Me, Nothing) '当前分页数字改变时,触发委托事件
            RaiseEvent EventPaging(New EventArgs())
        End If

        If PageIndex > PageCount Then PageIndex = PageCount

        '初始化按钮
        BtnFirst.Enabled = True
        BtnPrev.Enabled = True
        BtnNext.Enabled = True
        BtnLast.Enabled = True
        BtnGo.Enabled = True

        If RecordCount = 0 OrElse PageCount = 1 Then '总记录为0或有且仅有一页
            BtnFirst.Enabled = False
            BtnPrev.Enabled = False
            BtnNext.Enabled = False
            BtnLast.Enabled = False
            BtnGo.Enabled = False
        ElseIf PageIndex = 1 Then '第一页
            BtnFirst.Enabled = False
            BtnPrev.Enabled = False
        ElseIf PageIndex = PageCount Then '最后一页
            BtnNext.Enabled = False
            BtnLast.Enabled = False
        End If
    End Sub
#End Region

#Region "相关控件事件"
    Private Sub BtnFirst_Click(sender As Object, e As EventArgs) Handles BtnFirst.Click
        PageIndex = 1
        DrawControl(True)
    End Sub

    Private Sub BtnPrev_Click(sender As Object, e As EventArgs) Handles BtnPrev.Click
        PageIndex = Math.Max(1, PageIndex - 1)
        DrawControl(True)
    End Sub

    Private Sub BtnNext_Click(sender As Object, e As EventArgs) Handles BtnNext.Click
        PageIndex = Math.Min(PageCount, PageIndex + 1)
        DrawControl(True)
    End Sub

    Private Sub BtnLast_Click(sender As Object, e As EventArgs) Handles BtnLast.Click
        PageIndex = PageCount
        DrawControl(True)
    End Sub

    ''' <summary>
    ''' enter键功能
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub txtPageNum_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtPageNum.KeyPress
        btnGo_Click(Nothing, Nothing)
    End Sub


    ''' <summary>
    ''' 跳转页数限制
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub txtPageNum_TextChanged(sender As Object, e As EventArgs) Handles txtPageNum.TextChanged
        Dim num As Integer = 0

        If Integer.TryParse(txtPageNum.Text.Trim(), num) AndAlso num > 0 Then

            If num > PageCount Then
                txtPageNum.Text = PageCount.ToString()
            End If
        End If
    End Sub

    ''' <summary>
    ''' 跳转
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnGo_Click(ByVal sender As Object, ByVal e As EventArgs) Handles BtnGo.Click
        Dim num As Integer = 0

        If Integer.TryParse(txtPageNum.Text.Trim(), num) AndAlso num > 0 Then
            PageIndex = num
            DrawControl(True)
        End If
    End Sub

    ''' <summary>
    ''' 标识每页记录条数是否改变,为True则重绘控件
    ''' </summary>
    Private isTextChanged As Boolean = False
    ''' <summary>
    ''' 改变每页记录条数
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub txtPageSize_TextChanged(sender As Object, e As EventArgs) Handles txtPageSize.TextChanged
        Dim num As Integer = 0

        If Not Integer.TryParse(txtPageSize.Text.Trim(), num) OrElse num <= 0 Then
            num = 100
            txtPageSize.Text = "100"
        Else
            isTextChanged = True
        End If

        PageSize = num
    End Sub
    ''' <summary>
    ''' 光标离开分页属性
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub txtPageSize_Leave(sender As Object, e As EventArgs) Handles txtPageSize.Leave
        If isTextChanged Then
            isTextChanged = False
            DrawControl(True)
            'BtnFirst_Click(Nothing, Nothing)
        End If
    End Sub
#End Region
End Class

代码重点解读:

1、Windows窗体控件库继承自UserControl类,即:

Public Class DataGridViewPaging
    Inherits UserControl

End Class

2、委托事件:

如下定义了分页委托事件。

#Region "页码变化触发事件"
    'Public Event OnPageChanged As EventHandler
    Public Delegate Sub EventPagingHandler(ByVal e As EventArgs)
    Public Event EventPaging As EventPagingHandler
#End Region

然后引发事件。

''' <summary>
    ''' 页面控件呈现
    ''' </summary>
    ''' <param name="callEvent">是否触发事件,Ture则触发</param>
    ''' <remarks></remarks>
Private Sub DrawControl(ByVal callEvent As Boolean)
        If callEvent Then
            'RaiseEvent OnPageChanged(Me, Nothing) '当前分页数字改变时,触发委托事件
            RaiseEvent EventPaging(New EventArgs())
        End If
End Sub

 添加好代码后就可以测试了:调试——开始调试,如图所示。

测试分页控件

四、调用分页控件

1、为项目添加新项:如图所示,添加一个Windows窗体。

添加测试用的窗体

 2、从工具箱向Form1.vb中添加一个DataGridView控件和刚才做好的分页控件DataGridViewPaging。

打开工具箱,就会见到分页控件,如图所示,如果没有看到,你需要重新生成或调试一次就可以看到。

工具箱里的分页控件

3、向Form1.vb编写代码。

窗体加载时订阅事件:AddHandler Me.DataGridViewPaging1.EventPaging, AddressOf DataGridViewPaging1_EventPaging;

绑定方法:Private Sub DataGridViewPaging1_EventPaging(e As EventArgs)

                    End Sub

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.DataGridView1.AllowUserToAddRows = False
        '订阅事件
        AddHandler Me.DataGridViewPaging1.EventPaging, AddressOf DataGridViewPaging1_EventPaging
        Me.DataGridViewPaging1.DrawControl(0)
    End Sub

    ''' <summary>
    ''' 关联事件的方法,加载数据库的数据
    ''' </summary>
    ''' <param name="e"></param>
    Private Sub DataGridViewPaging1_EventPaging(e As EventArgs)
        If Me.DataGridView1.Rows.Count > Me.DataGridViewPaging1.PageSize Then
            For i As Integer = Me.DataGridView1.Rows.Count - 1 To Me.DataGridViewPaging1.PageSize Step -1
                Me.DataGridView1.Rows.Remove(Me.DataGridView1.Rows(i))
            Next
        ElseIf Me.DataGridView1.Rows.Count < Me.DataGridViewPaging1.PageSize Then
            Me.DataGridView1.Rows.Add(Me.DataGridViewPaging1.PageSize - Me.DataGridView1.Rows.Count)
        End If

        If Me.DataGridViewPaging1.RecordCount = 0 Then Exit Sub

        Dim j As Integer = -1
        For i As Integer = Me.DataGridViewPaging1.CurrentPageFirstRecord To Me.DataGridViewPaging1.CurrentPageLastRecord
            j += 1
            Me.DataGridView1.Rows(j).Cells(0).Value = i
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Me.DataGridViewPaging1.DrawControl(Integer.Parse(Me.TextBox1.Text))
    End Sub
End Class

4、设置项目属性。

设置应用程序类型为Windows窗体应用程序,启动对象设置为Form1。

重新设置项目属性

5、开始调试。效果如开头效果图。

调试问题:1、修改每页记录文本框时,页面不能正确显示当前页。如图所示。

2、修改跳转页码文本框的页码大于总页码时,没有点击跳转按钮就会触发事件,也就是代码运行顺序是不是存在一定问题,有待各位拍砖。

3、很迷惑,控件开头的命名空间为何可以不用导入?

​
'问题:这些命名空间都用不上吗?
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Public Class DataGridViewPaging
    Inherits UserControl

End Class

​

本文代码借鉴和参考了以下博文:

1、WinForm轻松实现自定义分页

2、Winform 通用分页控件实战篇(提供源码下载) 

学习过程得到网友uruseibest的帮助,表示感谢! 

猜你喜欢

转载自blog.csdn.net/zyjq52uys/article/details/85334780