You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB中两窗体互相持有实例是否存在风险?求替代实现方案

双向窗体引用的问题与替代实现方案

一、双向引用的潜在问题

你当前的实现中,主窗体持有修改窗体实例,修改窗体又持有主窗体实例,形成双向引用。从运行层面看,只要两个窗体都正常释放(比如修改窗体关闭后触发Disposed、主窗体重新显示),一般不会直接导致内存泄漏——.NET的GC可以处理这种循环引用。但从设计角度:

  • 违反单一职责原则:修改窗体的核心功能是编辑数据,它没必要知道主窗体的存在和显示逻辑。
  • 降低代码可维护性:如果后续主窗体类型修改,修改窗体的代码也要跟着调整。
  • 增加耦合度:两个窗体绑定在一起,无法单独复用修改窗体到其他场景。

二、更优雅的替代实现方式

方式1:使用模态对话框(推荐)

用ShowDialog()显示修改窗体,主窗体无需隐藏(会自动被禁用),修改窗体关闭后自动回到主窗体,且不需要持有主窗体实例。

主窗体代码:

Private Sub dgvNotas_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgvNotas.CellDoubleClick
    ' 转换DataSource为DataTable,获取选中行
    Dim dataTable As DataTable = DirectCast(dgvNotas.DataSource, DataTable)
    Dim selectedRow As DataRow = dataTable.Rows(e.RowIndex)

    ' Using语句自动释放窗体资源
    Using ventanaMod As New Modificar(selectedRow)
        ' 显示模态对话框,阻塞当前线程直到窗体关闭
        If ventanaMod.ShowDialog() = DialogResult.OK Then
            ' 编辑完成后刷新DataGridView
            dgvNotas.Refresh()
        End If
    End Using
End Sub

修改窗体代码:

Private _registro As DataRow

Public Sub New(registro As DataRow)
    InitializeComponent()
    _registro = registro
    ' 初始化控件值
    lblName.Text = registro("Nombre").ToString()
    lblApellidos.Text = registro("Apellidos").ToString()
    txtCiclo.Text = registro("Ciclo").ToString()
    txtCurso.Text = registro("Curso").ToString()
    txtVB.Text = registro("Nota1").ToString()
    txtAndr.Text = registro("Nota2").ToString()
    txtPy.Text = registro("Nota3").ToString()
    txtAws.Text = registro("Nota4").ToString()
    txtNav.Text = registro("Nota5").ToString()
    txtWpf.Text = registro("Nota6").ToString()
    txtEmpr.Text = registro("Nota7").ToString()
    txtEng.Text = registro("Nota8").ToString()
    TxtQV.Text = registro("Nota9").ToString()
End Sub

' 保存按钮逻辑
Private Sub btnGuardar_Click(sender As Object, e As EventArgs) Handles btnGuardar.Click
    ' 更新DataRow数据
    _registro("Nombre") = lblName.Text
    _registro("Apellidos") = lblApellidos.Text
    _registro("Ciclo") = txtCiclo.Text
    _registro("Curso") = txtCurso.Text
    _registro("Nota1") = txtVB.Text
    _registro("Nota2") = txtAndr.Text
    _registro("Nota3") = txtPy.Text
    _registro("Nota4") = txtAws.Text
    _registro("Nota5") = txtNav.Text
    _registro("Nota6") = txtWpf.Text
    _registro("Nota7") = txtEmpr.Text
    _registro("Nota8") = txtEng.Text
    _registro("Nota9") = TxtQV.Text

    ' 设置对话框结果,通知主窗体编辑完成
    DialogResult = DialogResult.OK
    Close()
End Sub

' 取消按钮逻辑
Private Sub btnCancelar_Click(sender As Object, e As EventArgs) Handles btnCancelar.Click
    DialogResult = DialogResult.Cancel
    Close()
End Sub

方式2:使用事件通知

修改窗体定义一个编辑完成的事件,主窗体订阅该事件,触发后重新显示自己,避免双向引用。

修改窗体代码:

' 定义编辑完成事件
Public Event EdicionCompletada()

Private _registro As DataRow

Public Sub New(registro As DataRow)
    InitializeComponent()
    _registro = registro
    ' 初始化控件(同方式1)
End Sub

Private Sub btnGuardar_Click(sender As Object, e As EventArgs) Handles btnGuardar.Click
    ' 更新DataRow数据(同方式1)
    RaiseEvent EdicionCompletada() ' 触发事件
    Close()
End Sub

主窗体代码:

Private Sub dgvNotas_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgvNotas.CellDoubleClick
    Dim dataTable As DataTable = DirectCast(dgvNotas.DataSource, DataTable)
    Dim selectedRow As DataRow = dataTable.Rows(e.RowIndex)

    Dim ventanaMod As New Modificar(selectedRow)
    ' 订阅编辑完成事件
    AddHandler ventanaMod.EdicionCompletada, AddressOf MostrarFormularioPrincipal
    Me.Hide()
    ventanaMod.Show()
End Sub

Private Sub MostrarFormularioPrincipal()
    Me.Show()
    dgvNotas.Refresh()
End Sub

方式3:通过Application.OpenForms获取主窗体(不推荐)

如果坚持要隐藏主窗体,可以通过Application.OpenForms查找主窗体实例,不需要修改窗体持有主窗体引用,但这种方式依赖窗体名称/类型,灵活性差:

修改窗体代码:

Private Sub Modificar_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
    ' 根据窗体类型查找主窗体
    Dim mainForm As Form1 = DirectCast(Application.OpenForms.OfType(Of Form1).FirstOrDefault(), Form1)
    mainForm?.Show()
End Sub

总结

双向引用虽然能正常运行,但不是最佳实践。优先选择模态对话框的实现方式,它更简洁、符合WinForms的设计习惯,且代码耦合度低;如果需要非模态显示,用事件通知的方式更优雅。

内容的提问来源于stack exchange,提问作者Alex Medina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 15:50:17