【问题标题】:VB.NET - Access menu event from another form, works only on form_loadVB.NET - 从另一个表单访问菜单事件,仅适用于 form_load
【发布时间】:2012-09-09 22:03:49
【问题描述】:

我的应用程序中有两种表单,一种是创建新连接,另一种是主表单,其中包含带有连接名称的菜单。

当我在frmNewConnection 表单下创建新连接并尝试单击生成的菜单项时,它不会像我重新打开程序时那样显示测试消息。

在主窗体中,我有以下公共子窗体。

主窗体frmMain

Public Sub Connect_SubMenuItem_Click(ByVal sender As Object, ByVal e As EventArgs)
  Messagebox.Show("Test")
End Sub

除非我重新启动我的应用程序,否则该代码永远不会被执行,然后当我单击新生成的菜单项时它工作正常。但是,如果我要加载应用程序并单击“新建连接”菜单项并创建新连接,然后尝试在“连接”菜单下单击它,则没有任何反应,我没有收到“测试”消息框。

我在 frmNewConnection Accept 按钮下有如下代码,它将连接的名称保存到“Connections”菜单中。

frmMain.menuConnections.DropDownItems.Add(ConnectionName, Nothing, AddressOf frmMain.Connect_SubMenuItem_Click) ' save to menu

我还有一个在 frmMain_load() 上执行的代码版本:

menuConnections.DropDownItems.Add(finalData(1).ToString, Nothing, AddressOf Connect_SubMenuItem_Click) ' save to menu

我的问题是,为什么在程序中生成新菜单项时不会出现测试消息,但是当我关闭程序并重新打开它时它会显示..

【问题讨论】:

  • 这段代码中使用“Form1”是VB.NET的悲剧。它是一个类型名称,而不是引用用户正在查看的 Form1 对象的变量。继承自 VB6,一种根本不支持线程的语言。当您确实使用线程时,它会爆炸。就像 BeginConnect() 方法调用的回调一样。现在您在另一个线程上运行代码,该线程创建 Form1 的 new 实例。不可见是因为您没有调用它的 Show() 方法,而功能失调是因为线程不泵送消息循环。一只死鹦鹉。
  • @Hans Passant,这很有趣,我完全不知道。谢谢你提供的信息。将 form1 重命名为诸如 frmMain 之类的唯一名称就足够了吗?
  • 不,重命名表单是不够的。您需要将项目添加到您之前使用的 Form1 的特定实例的下拉列表中。
  • 我一直在尝试获取 Form1 的正确实例,有什么提示吗?

标签: .net vb.net events


【解决方案1】:

如果您要从另一个表单修改一个表单的控件,那么您可能会搞错整个事情。

您需要做的第一件事是控制您的程序启动。 VB 有时会隐藏这一点。这将允许您捕获表单变量。然后,考虑重构一下。

一些 VB.NET 伪代码(对于此处泄露的任何 C#,我深表歉意):

Class Program

   Private _appCtx As AppContext

   Sub Main()

      _appCtx = New AppContext()

      'perform whatever bootstrap logic you needed here, typically
      ' configuring and installing behaviors into the app context
      '
      '

      ' one single instace of your main form
      _appCtx.RootForm = New frmMain(); 'or better still, pass AppContext into the ctor 

      Application.Run(_appCtx.RootForm)

   End Sub

   'if you want to cheat a bit, include this getter to provide access to everyone
   'otherwise, pass the app context to those classes that require it
   Public Shared AppCtx() As AppContext
      Get
         return _appCtx
      End Get
   End Property


End Class

Public Class AppContext

   Public Property RootForm As Form

   Public Property Connections As Connections

   'other application-wide subsystems or data

End Class

Public Class Connections

   Public Event Changed As EventHandler

   Public Property Count As Integer

   'other properties including a getter for the child connection objects...

   Public Sub Add(newConn As Connection)
      'add to internal list then...
      If Changed IsNot Nothing Then
         Changed(this, EventArgs.Empty)
      End If
   End Sub

End Class

Public Class frmMain


   Sub Form_Load() 

      AddHandler AppCtx.Connections.Changed AddressOf(Connections_Changed)

   End Sub

   Sub Connections_Changed()
      'iterate the connections and refresh the menu
      'the menu gets refreshed without breaking encapsulation!
   End Sub

End Class

Public Class frmNewConnection 


   private sub Accept_Click()

      'do stuff to create a connection object

      'add to the current set of connections, this will broadcast to anyone who needs to know      
      AppCtx.Connection.Add(newConn)

   End Sub 

End Class

如果您不想使用域对象事件进行更新,这取决于您,但示例的第一部分展示了如何将启动表单捕获到一个变量中,然后您可以在程序代码中使用该变量.

【讨论】:

    【解决方案2】:

    将菜单项添加到菜单后,您需要为其添加处理程序:

    Private Sub btnAddMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddMenuItem.Click
        Dim tsmi As New ToolStripMenuItem("Test")
        Me.MenuStrip1.Items.Add(tsmi)
        AddHandler tsmi.Click, AddressOf Me.TestMenu
    End Sub
    
    Private Sub TestMenu(ByVal Sender As Object, ByVal e As System.EventArgs)
        MessageBox.Show("Test Menu")
    End Sub
    

    【讨论】:

    • 我测试了这个没有运气,记住这里的问题是我在添加带有事件的新菜单项时处于不同的形式。使用“我”不起作用,因为 menuItem 是另一种形式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 2014-11-22
    • 2016-05-06
    相关资源
    最近更新 更多