Dev
Dev

Reputation: 1826

How to show menu text in custom ToolStripItem?

Mainform VB.Net:

<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()>
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()>
    Private Sub InitializeComponent()
        Me.tsBasket = New System.Windows.Forms.ToolStrip()
        Me.tsiFruit = New System.Windows.Forms.ToolStripDropDownButton()
        Me.tsBasket.SuspendLayout()
        Me.SuspendLayout()
        '
        'tsBasket
        '
        Me.tsBasket.Dock = System.Windows.Forms.DockStyle.None
        Me.tsBasket.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden
        Me.tsBasket.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.tsiFruit})
        Me.tsBasket.Location = New System.Drawing.Point(355, 213)
        Me.tsBasket.Name = "tsBasket"
        Me.tsBasket.Size = New System.Drawing.Size(121, 25)
        Me.tsBasket.TabIndex = 5
        '
        'tsiFruit
        '
        Me.tsiFruit.ImageTransparentColor = System.Drawing.Color.Magenta
        Me.tsiFruit.Name = "tsiFruit"
        Me.tsiFruit.Size = New System.Drawing.Size(87, 22)
        Me.tsiFruit.Text = "add fruit"
        '
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(800, 450)
        Me.Controls.Add(Me.tsBasket)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.tsBasket.ResumeLayout(False)
        Me.tsBasket.PerformLayout()
        Me.ResumeLayout(False)
        Me.PerformLayout()

    End Sub

    Friend WithEvents tsBasket As ToolStrip
    Friend WithEvents tsiFruit As ToolStripDropDownButton
End Class

Form Load:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim men As New TestTool()
    men.Text = "showmeplease"
    men.Image = Nothing
    men.NewProperty = "BO"

    Dim men2 As New TestTool()
    men2.Text = "showmeplease2"
    men2.Image = Nothing
    men2.NewProperty = "BO2"

    tsiFruit.DropDownItems.Add(men)
    tsiFruit.DropDownItems.Add(men2)
    AddHandler men.Click, AddressOf tsiType_Click
    AddHandler men2.Click, AddressOf tsiType_Click
End Sub

Private Sub tsiType_Click(sender As System.Object, e As System.EventArgs)
    Dim MenuItem As TestTool = DirectCast(sender, TestTool)
    MessageBox.Show(MenuItem.NewProperty & "  " & MenuItem.Text)
End Sub

Custom class:

Public Class TestTool
    Inherits ToolStripItem

    Private newPropertyValue As String
    Public Property NewProperty() As String
        Get
            Return newPropertyValue
        End Get
        Set(ByVal value As String)
            newPropertyValue = value
        End Set
    End Property

    Sub New()

        ' This call is required by the designer.
        ' InitializeComponent()

    End Sub
End Class

On my custom class/Usercontrol I am getting : The designer must create an instance of type 'System.Windows.Forms.ToolStripItem' but it cannot because the type is declared as abstract. and I am not seeing the text appear in the menu items, but the click event works fine.

Is this the correct way to extend(Inherit using OO) a ToolMenuStrip so that I can have a Display value and a Member value, I want to be able to store an object without using .Tag.

Edit: I am getting when trying to have nested menus:

System.InvalidCastException: 'Unable to cast object of type 'System.Windows.Forms.ToolStripMenuItem' to type 'WindowsApp1.TestTool'.'

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim men As New TestTool()
    men.Text = "showmeplease"
    men.Image = Nothing
    men.NewProperty = "BO"

    Dim men2 As New TestTool()
    men2.Text = "showmeplease2"
    men2.Image = Nothing
    men2.NewProperty = "BO2"

    tsiFruit.DropDownItems.Add(men)
    tsiFruit.DropDownItems.Add(men2)

    Dim TypeMenuItem As TestTool = men.DropDownItems.Add("hh")

    For Each mInfo As String In Moreinfo
        TypeMenuItem.DropDownItems.Add(mInfo, Nothing, AddressOf tsiType_Click)
    Next
    AddHandler men.Click, AddressOf tsiType_Click
    AddHandler men2.Click, AddressOf tsiType_Click
End Sub

Private p_Moreinfo As List(Of String)
Public Property Moreinfo() As List(Of String)
    Get

        Dim test As New List(Of String)
        test.Add("A")
        test.Add("B")
        Return test
    End Get
    Set(ByVal value As List(Of String))
        p_Moreinfo = value
    End Set
End Property

Upvotes: 1

Views: 155

Answers (1)

dr.null
dr.null

Reputation: 4660

If you enable the Option Strict check (you should), you will find an error with the line below in the Form1_Load event:

' Error: Option Strict On disallows implicit conversions from ToolStrinpItem
' to TestTool.
Dim TypeMenuItem As TestTool = men.DropDownItems.Add("hh")

Because the .DropDownItems.Add(String) overload returns a ToolStripItem and not an object of type TestTool. The .DropDownItems don't inherit the type of the owner item.

' Compiles.
Dim TypeMenuItem As ToolStripItem = men.DropDownItems.Add("hh")

' Compiles.
Dim TypeMenuItem As ToolStripMenuItem = DirectCast(men.DropDownItems.Add("hh"), ToolStripMenuItem)

' Throws System.InvalidCastException.
Dim TypeMenuItem As TestTool = DirectCast(men.DropDownItems.Add("hh"), TestTool)

So, the code in Load event should be like:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim men As New TestTool With {
        .Text = "showmeplease",
        .NewProperty = "BO"
    }

    Dim men2 As New TestTool With {
        .Text = "showmeplease2",
        .NewProperty = "BO2"
    }

    tsiFruit.DropDownItems.Add(men)
    tsiFruit.DropDownItems.Add(men2)

    Dim TypeMenuItem As New TestTool() With {.NewProperty = "hh", .Text = "SomeText"}

    men.DropDownItems.Add(TypeMenuItem)

    For Each mInfo As String In Moreinfo
        Dim item = New TestTool With {.NewProperty = mInfo, .Text = "SomeText"}
        AddHandler item.Click, AddressOf tsiType_Click
        TypeMenuItem.DropDownItems.Add(item)
    Next

    AddHandler men.Click, AddressOf tsiType_Click
    AddHandler men2.Click, AddressOf tsiType_Click
End Sub

Likewise, to avoid throwing exceptions in the tsiType_Click event, just in case:

Private Sub tsiType_Click(sender As Object, e As EventArgs)
    Dim item = TryCast(sender, TestTool)

    If item IsNot Nothing Then
        MessageBox.Show($"{item.NewProperty} {item.Text}")
    Else
        MessageBox.Show(DirectCast(sender, ToolStripItem).Text)
    End If
End Sub

I believe you have modified the TestTool class as @jmcilhinney commented to something like:

Public Class TestTool
    Inherits ToolStripMenuItem

    Sub New()
        MyBase.New
    End Sub

    Public Property NewProperty As String

End Class

Upvotes: 1

Related Questions