VB.NET 绝对奇怪的表单加载行为

标签 vb.net winforms visual-studio-2012 right-to-left

我在使用 RightToLayout 布局时遇到了一个奇怪的行为: 我的表单会自动关闭。

我创建了一个简单的项目来重现该问题:

在VS2012中新建一个VB.NET工程,添加窗体“Form1”和“Form2”。 将“Form1”设置为起始表单。

然后在“Form1”中添加如下代码:

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load

        Me.Hide()

        Dim f As New Form2
        f.ShowDialog()

        MessageBox.Show("After dialog closed.")

        modControls.setFormRTL(Me) 'This line causes the Form2 to automatically close. Why??? This line should only be processed AFTER the dialog has been shown and closed

    End Sub
End Class

将以下代码添加到“Form2”:

Public Class Form2

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles Me.Load

        modControls.setFormRTL(Me)

    End Sub
End Class

将名为“modControls”的模块添加到项目中。 向其中添加以下代码:

Module modControls

    Public Sub setFormRTL(ByVal uForm As Form)

        uForm.RightToLeft = RightToLeft.Yes

    End Sub

End Module

没有 setFormRTL,我的项目工作得很好,但有了它,“Form2”会自动关闭。您可以看到这一点,因为显示了消息框。

当我删除行时

        modControls.setFormRTL(Me)

从 Form1 加载,它再次正常工作。 是的,我的意思是来自“Form1”,而不是来自“Form2”!!!

现在这真的很奇怪,因为它根本不重要,因为在关闭对话框之前没有处理这一行。 我希望有人明白我的意思。

任何人都可以阐明这里可能发生的事情吗?

最佳答案

是的,如果您在控件的构造函数以外的任何位置设置 RightToLeft 属性(用 VB.NET 的说法,即 New 方法),您将获得意想不到的行为。

事实上,构造函数是您应该设置窗体或控件对象的所有 属性的地方。如果您来自 VB 6,在 Load 事件处理程序中执行此操作似乎合乎逻辑,但这不是惯用的 .NET,并且正如您所发现的那样,在初始化某些属性时可能会导致问题。

这样做的技术原因是某些属性(如 RightToLeft)实际上只能在 native 窗口上设置(这就是 Form 对象在 . NET 世界在创建时在幕后实现)。当您尝试更改属性时,框架代码实际上必须销毁然后使用新的属性值重新创建 native 窗口。

将代码改为如下所示:

Public Class Form1

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        modControls.SetFormRtl(Me)
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Me.Hide()

        Dim f As New Form2
        f.ShowDialog()

        MessageBox.Show("After dialog closed.")
    End Sub
End Class

Public Class Form2

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        modControls.SetFormRtl(Me)
    End Sub

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles Me.Load

    End Sub
End Class

说到非惯用的 .NET 代码:

  1. 按照惯例,所有方法都应采用 Pascal 大小写。这意味着您的 setFormRTL 方法应命名为 SetFormRtl

  2. 设置对象属性的辅助函数对我来说似乎是错误的。如果有的话,那就是糟糕的 OO 设计。如果您希望此方法可用于所有 Form 对象,请派生一个自定义表单类并添加此方法(或者甚至在构造函数中执行所需的初始化)。无论哪种方式,您从这个自定义表单对象派生的所有表单都将继承该功能。示例:

    Public Class MyCustomForm : Inherits System.Windows.Forms.Form
    
        Public Sub New()
            MyBase.New()
    
            Me.SetRtl()
        End Sub
    
        Public Sub SetRtl()
            Me.RightToLeft = RightToLeft.Yes
        End Sub
    
    End Class
    
    Public Class Form1 : Inherits MyCustomForm
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
            Me.Hide()
    
            Dim f As New Form2
            f.ShowDialog()
    
            MessageBox.Show("After dialog closed.")
        End Sub
    
    End Class
    
    Public Class Form2 : Inherits MyCustomForm
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles Me.Load
    
        End Sub
    
    End Class
    

关于VB.NET 绝对奇怪的表单加载行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23356312/

相关文章:

mysql - 使用 VB.net 更改 MySQL 中表的列名

c# - 文件名未传递给 main

VB.NET:保持类命名空间与文件夹结构同步

vb.net - .NET 确定控件的值已更改并最终确定

sql - Vb.net - 数组、数据库或 sql

c# - 带有 VS2010 的 .NET 3.5 控制图

c# - listViewItem.BackColor 不工作

svn - 我应该使用什么插件将 TortoiseSVN 集成到 Windows 8 上的 Visual Studio 2012 中?

c++ - 无法打开文件 'SOIL.libkernel32.lib'

.net - 在 VS 2012 中保存/导出单元测试结果