VB.NET學習筆記:WinForm自定義DataGridView分頁組合控制元件
測試環境:windows 7和Microsoft Visual Studio 2015
VB.NET雖然提供了大量控制元件供我們使用,但很多控制元件僅提供最基礎的功能。比如用DataGridView控制元件可以非常方便顯示或操作資料庫資料, 但卻沒有分頁功能。本文介紹通過自定義窗體庫組合VB.NET已有控制元件實現DataGridView控制元件分頁顯示功能。
測試效果如圖:
這其實就是一個組合控制元件(CompositeControls),繼承自UserControl類,將目前現有的控制元件根據需要組合到一起形成一個新的控制元件。具體做法如下:
一、新建Windows窗體控制元件庫專案
如下圖所示,名稱按你喜歡的寫上就行。Windows窗體控制元件庫有視覺化的設計檢視,可以從工具箱新增VB.NET中已有的控制元件。
如果新建的是Windows窗體應用程式,也可以通過右鍵單擊解決方案資源管理器中的專案名稱,在彈出的右鍵選單中點選“新增”-“新建項”,在彈出的“新建專案”視窗中選擇“使用者控制元件”,這個也是建自定義組合控制元件的,如下圖所示。
二、佈局
在設計窗口裡新增如下圖所示的控制元件。
佈局技巧分享:
1、按鈕外觀美化:如下圖設定按鈕的FlatAppearance的BorderSize為0,即去除邊框,FlatStyle為Flat,即按鈕外觀為平面顯示,通過Image屬性為按鈕新增圖片。
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
本文程式碼借鑑和參考了以下博文:
2、Winform 通用分頁控制元件實戰篇(提供原始碼下載)
學習過程得到網友uruseibest的幫助,表示感謝!