【问题标题】:VB.NET Absolutely strange form load behaviourVB.NET 绝对奇怪的表单加载行为
【发布时间】:2014-06-14 21:33:19
【问题描述】:

我在使用 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”!!!

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

谁能解释一下这里可能发生的事情?

【问题讨论】:

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


    【解决方案1】:

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

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

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

    将代码改为如下所示:

    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
      

    【讨论】:

    • +1 但实际上setFormRTL 应该命名为SetFormRtl : msdn.microsoft.com/en-us/library/ms229043.aspx
    • 确实...我总是忘记在从事明确未遵循特定约定的项目之后。我想,习惯的力量。更新了我的答案。
    • @CodyGray 你能为以下场景提出一些建议吗?我正在使用应用程序框架,因此我有一个启动表单。但是在主窗体的“新建”事件中,我还不知道用户是否为我的应用程序选择了 RTL 语言,所以我还不能在那里设置它。我正在表单加载事件中对其进行评估。我应该简单地将 RTL 评估填充到 New 事件中吗?
    • @tmighty 是的,检测代码仍然在构造函数中(即 New 方法)。确定您的表单是否应该是 RTL 就像检查 CultureInfo.CurrentCulture.TextInfo.IsRightToLeft 属性一样简单。这将返回有关当前使用的语言设置的信息。
    • @CodyGray 在我的应用程序中,用户可以选择不同的语言。我将所选语言存储在数据库中,因此我还需要在 New 构造函数中打开数据库。这完全没问题,还是应该只将 New 构造函数用于“简单的东西”而不是像 DB 打开这样繁重的东西?
    【解决方案2】:

    你可以试试这个吗?我在这里所做的只是在显示表单之前设置 RTL。

    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    
            Me.Hide()
    
            Dim f As New Form2
            modControls.setFormRTL(f)
            f.ShowDialog()
    
            MessageBox.Show("After dialog closed.")
    
            modControls.setFormRTL(Me)
    
        End Sub
    End Class
    

    并移除表单2的代码表单加载事件

    【讨论】:

    • 哇,这行得通,即使我没有从 Form2 的加载事件中删除代码。但我真的需要知道为什么。你有什么想法??我认为 Form Load 事件是正确的地方。我真的很想在表格内的某个地方做,而不是像你的例子那样从“外面”做。
    • 另外,我不确定如何在创建表单句柄之前设置 RightToLeftLayout 属性。
    猜你喜欢
    • 1970-01-01
    • 2019-02-22
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    相关资源
    最近更新 更多