Поймать исключение в итерации элементов ContextMenuStrip

Я пытаюсь перебирать элементы contextmenustrip следующим образом:

Public Sub TranslateContextMenuStrip(ByRef u As ContextMenuStrip)

    For Each t As ToolStripMenuItem In u.Items 'here the error occurs
        pProcessMenuItem(t) 'not here
    Next

End Sub

Но у меня есть разделители панели инструментов в строке контекстного меню, и я получаю сообщение об ошибке

«System.InvalidCastException: объект типа System.Windows.Forms.ToolStripSeparator не может быть преобразован в тип System.Windows.Forms.ToolStripMenuItem»

как только он спотыкается о разделитель.

Интересно, почему этот разделитель включен в элементы (я запрашиваю «Для каждого t как ToolStripMenuItem», так почему он возвращает не-ToolStripMenuItems???) и как поймать эту ошибку или избежать ее.


person Maiken Roskilde    schedule 11.01.2016    source источник


Ответы (2)


Я нашел решение, но не проблему:

    For Each it As Object In u.Items
        If TypeOf it Is ToolStripMenuItem Then
            pProcessMenuItem(it)
        End If
    Next
person Maiken Roskilde    schedule 12.01.2016

Я не думаю, что For Each t As ToolStripMenuItem делает то, что вы думаете.

Он просто объявляет, что итератор t будет иметь тип ToolStripMenuItem. Он ничего не делает с самой коллекцией элементов. Когда вы приходите к разделителю, вы получаете исключение приведения, потому что разделитель не может быть преобразован в пункт меню.

Items представляет собой набор ToolStripItems. Это базовый класс, используемый для всех типов, которые может содержать контекстное меню (элемент меню, комбо, текстовое поле или разделитель). Поскольку все они наследуются от ToolStripItem, коллекция может содержать любой из них (в частности, элемент ToolStripSeparator также является ToolStripItem).

Существует несколько способов итерации или работы только с пунктами меню:

Фильтровать коллекцию Items

For Each tsi As ToolStripMenuItem In u.Items.OfType(Of ToolStripMenuItem)()
    ' do something fun with tsi
Next

Расширение OfType() фильтрует коллекцию элементов до элементов меню.

Это, безусловно, самое простое, потому что ваш итератор tsi является правильным типом. Это особенно верно, если ваш метод написан для ожидания пунктов меню:

Sub pProcessMenuItem(item As ToolStripMenuItem)

Итератор tsi имеет тип, ожидаемый методом, поэтому дальнейшие шаги не требуются. Все остальное потребует приведения либо в методе, либо для вызова метода (или Option Strict Off).

Проверьте тип:

' iterate all the items 
For Each tsi As ToolStripItem In u.Items
    ' test the type of each 
    If TypeOf tsi Is ToolStripMenuItem Then
        ' do something fun with tsi
    End If
Next

При передаче Option Strict tsi в метод, объявленный, как показано выше, компилироваться не будет. Вам нужно будет выполнить бросок перед вызовом вашего метода:

pProcessMenuItem(CType(tsi, ToolStripMenuItem))

Если объявлено, что метод принимает ToolStripItem или Object, приведение должно выполняться в методе, если вам нужно получить доступ к каким-либо свойствам, связанным с меню.


То же самое верно и при использовании As Object для итерации:

For Each it As Object In u.Items
    If TypeOf it Is ToolStripMenuItem Then
        pProcessMenuItem(it)
    End If
Next

Единственный способ компилировать под Option Strict, если аргумент метода объявлен As Object. Как и выше, Object, возможно, придется преобразовать в ToolStripMenuItem. Первый метод исключает необходимость в этом.

person Ňɏssa Pøngjǣrdenlarp    schedule 11.01.2016