关于 vb-winforms
此技能为使用 VB.NET 开发 Windows Forms 应用的开发者提供实践模式,涵盖 UI 线程、数据绑定、事件处理、验证和对话框。
主要功能
- 01UI 线程与后台任务模式
- 02BindingSource 数据绑定
- 03事件处理模式
- 04表单验证
- 05自定义对话框模式
适用场景
- 01后台任务期间更新表单
- 02将客户数据绑定到控件
- 03保存前验证表单输入
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bobmatnyc/ claude-mpm-skills --skill vb-winforms安装后在 Claude Code 中输入/vb-winforms确认已加载。
附带文件metadata.json
详细介绍
Visual Basic Windows 窗体模式
现代 Windows 窗体开发,使用 VB.NET 并专注于正确的 UI 线程处理、数据绑定和事件处理。
快速入门
' Form definition
Public Class CustomerForm
Inherits Form
Private customerService As ICustomerService
Private bindingSource As New BindingSource()
Public Sub New()
InitializeComponent()
customerService = New CustomerService()
End Sub
' Async load
Private Async Sub CustomerForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Await LoadCustomersAsync()
End Sub
Private Async Function LoadCustomersAsync() As Task
Try
Cursor = Cursors.WaitCursor
Dim customers = Await customerService.GetAllAsync()
bindingSource.DataSource = customers
dataGridView.DataSource = bindingSource
Catch ex As Exception
MessageBox.Show($"Error loading customers: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
Cursor = Cursors.Default
End Try
End Function
End Class
UI 线程处理模式
Invoke 与 BeginInvoke
' Update UI from background thread
Private Sub BackgroundWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
' Already on UI thread with BackgroundWorker
progressBar.Value = e.ProgressPercentage
lblStatus.Text = $"Processing: {e.ProgressPercentage}%"
End Sub
' Manual invoke when needed
Private Sub UpdateUIFromThread(text As String)
If lblStatus.InvokeRequired Then
lblStatus.Invoke(Sub() lblStatus.Text = text)
Else
lblStatus.Text = text
End If
End Sub
' Async pattern
Private Async Sub btnProcess_Click(sender As Object, e As EventArgs) Handles btnProcess.Click
btnProcess.Enabled = False
Try
Dim result = Await Task.Run(Function() LongRunningOperation())
lblResult.Text = result ' Safe - back on UI thread
Finally
btnProcess.Enabled = True
End Try
End Sub
BackgroundWorker 模式
Private WithEvents bgWorker As New BackgroundWorker With {
.WorkerReportsProgress = True,
.WorkerSupportsCancellation = True
}
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
If Not bgWorker.IsBusy Then
bgWorker.RunWorkerAsync()
End If
End Sub
Private Sub bgWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgWorker.DoWork
For i = 0 To 100
If bgWorker.CancellationPending Then
e.Cancel = True
Exit For
End If
' Simulate work
Threading.Thread.Sleep(50)
bgWorker.ReportProgress(i)
Next
End Sub
Private Sub bgWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgWorker.ProgressChanged
progressBar.Value = e.ProgressPercentage
End Sub
Private Sub bgWorker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgWorker.RunWorkerCompleted
If e.Cancelled Then
MessageBox.Show("Operation cancelled")
ElseIf e.Error IsNot Nothing Then
MessageBox.Show($"Error: {e.Error.Message}")
Else
MessageBox.Show("Operation completed")
End If
End Sub
数据绑定
BindingSource 模式
Public Class CustomerForm
Private bindingSource As New BindingSource()
Private customers As List(Of Customer)
Private Async Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
customers = Await customerService.GetAllAsync()
' Setup binding source
bindingSource.DataSource = customers
' Bind controls
dataGridView.DataSource = bindingSource
txtName.DataBindings.Add("Text", bindingSource, "Name")
txtEmail.DataBindings.Add("Text", bindingSource, "Email")
' Navigation
bindingNavigator.BindingSource = bindingSource
End Sub
' Filter
Private Sub txtSearch_TextChanged(sender As Object, e As EventArgs) Handles txtSearch.TextChanged
If String.IsNullOrEmpty(txtSearch.Text) Then
bindingSource.RemoveFilter()
Else
bindingSource.Filter = $"Name LIKE '%{txtSearch.Text}%'"
End If
End Sub
End Class
对象数据绑定
' Customer class with INotifyPropertyChanged
Public Class Customer
Implements INotifyPropertyChanged
Private _name As String
Public Property Name As String
Get
Return _name
End Get
Set(value As String)
If _name <> value Then
_name = value
OnPropertyChanged(NameOf(Name))
End If
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
事件处理
标准事件模式
' Button click
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
If ValidateForm() Then
SaveCustomer()
End If
End Sub
' Multiple controls, same handler
Private Sub TextBox_TextChanged(sender As Object, e As EventArgs) _
Handles txtName.TextChanged, txtEmail.TextChanged
ValidateForm()
End Sub
' Custom event arguments
Public Class CustomerEventArgs
Inherits EventArgs
Public Property Customer As Customer
Public Sub New(customer As Customer)
Me.Customer = customer
End Sub
End Class
Public Event CustomerSaved As EventHandler(Of CustomerEventArgs)
Protected Sub OnCustomerSaved(customer As Customer)
RaiseEvent CustomerSaved(Me, New CustomerEventArgs(customer))
End Sub
窗体验证
Private Function ValidateForm() As Boolean
errorProvider.Clear()
Dim isValid = True
' Validate name
If String.IsNullOrWhiteSpace(txtName.Text) Then
errorProvider.SetError(txtName, "Name is required")
isValid = False
End If
' Validate email
If String.IsNullOrWhiteSpace(txtEmail.Text) OrElse Not txtEmail.Text.Contains("@") Then
errorProvider.SetError(txtEmail, "Valid email is required")
isValid = False
End If
' Enable/disable save button
btnSave.Enabled = isValid
Return isValid
End Function
' Real-time validation
Private Sub txtEmail_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) _
Handles txtEmail.Validating
If Not txtEmail.Text.Contains("@") Then
errorProvider.SetError(txtEmail, "Invalid email format")
e.Cancel = True
Else
errorProvider.SetError(txtEmail, "")
End If
End Sub
对话框模式
自定义对话框结果
Public Class CustomerDialog
Inherits Form
Public Property Customer As Customer
Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click
If ValidateForm() Then
Customer = New Customer With {
.Name = txtName.Text,
.Email = txtEmail.Text
}
DialogResult = DialogResult.OK
Close()
End If
End Sub
Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
DialogResult = DialogResult.Cancel
Close()
End Sub
End Class
' Usage
Private Sub ShowCustomerDialog()
Using dialog = New CustomerDialog()
If dialog.ShowDialog() = DialogResult.OK Then
' Use dialog.Customer
customers.Add(dialog.Customer)
RefreshGrid()
End If
End Using
End Sub
最佳实践
✅ 应该做
' Use async for I/O operations
Private Async Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim data = Await LoadDataAsync()
End Sub
' Dispose resources properly
Private Sub Form_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
connection?.Dispose()
timer?.Dispose()
End Sub
' Use BindingSource for data binding
bindingSource.DataSource = customers
dataGridView.DataSource = bindingSource
' Validate on events
Private Sub txtName_Validating(sender As Object, e As CancelEventArgs) Handles txtName.Validating
' Use ErrorProvider for validation feedback
errorProvider.SetError(txtName, "Name is required")
❌ 不要做
' Don't block UI thread
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim data = LoadDataAsync().Result ' Blocks UI!
End Sub
' Don't update UI from background thread directly
Task.Run(Sub()
lblStatus.Text = "Done" ' WRONG - cross-thread operation
End Sub)
' Don't forget to dispose forms
Dim form = New CustomerForm()
form.Show() ' Memory leak - use Using or handle FormClosed
' Don't use Application.DoEvents
While processing
Application.DoEvents() ' Bad practice - use async instead
End While
相关技能
- vb-core:VB.NET 核心模式和类型安全
- vb-database:与 Windows 窗体集成数据库
- test-driven-development:测试 Windows 窗体应用程序
评论
支持 Markdown