如何在显示ToolStripMenuItem时禁用或(取消)检查它?

时间:2015-02-06 00:04:37

标签: vb.net toolstripmenu

网上有几个关于如何禁用菜单项孩子的例子(例如,使用 DropDownOpening 事件),但是我想创建一个继承 ToolStripMenuItem 的类,并且可以自行决定是否应该启用它。

这样的事情:

Public Class SmartMenuItem
    Inherits ToolStripMenuItem

    Public Sub New(text As String)
        MyBase.New(text)
        AddHandler MyBase.VisibleChanged, AddressOf enableSelf
    End Sub

    Private Sub enableSelf(sender As Object, e As System.EventArgs)
        Me.Enabled = MagicFunctionBooleanResult()
    End Sub

End Class

但是 VisibleChanged 事件并不像我希望的那样工作,我也找不到任何其他事件。

我还为项目本身尝试了 DropDownOpening 事件,但是只会在相当长的时间内触发,因此,如果用户足够快,他们仍然可以在项目显示后单击该项目。

这似乎是一个显而易见的特征,我担心我会遗漏一些东西......很明显。

有什么想法吗?

编辑:改变 Checked 属性当然是同样的事情......

2 个答案:

答案 0 :(得分:0)

当您将鼠标悬停在项目上时,我确实设法看到您在使用自定义ToolStripMenuItem的DropDownOpening事件时引用的延迟。当您将鼠标悬停在该项目上时,它然后尝试打开任何子菜单,即使它没有任何子菜单。那是你看到的延迟。

尝试使用OwnerChanged事件代替知道父项目何时正在执行DropDownOpening事件:

Public Class SmartMenuItem
  Inherits ToolStripMenuItem

  Public Sub New(text As String)
    MyBase.New(text)
  End Sub

  Private Sub SmartMenuItem_OwnerChanged(sender As Object, e As EventArgs) _
                                         Handles Me.OwnerChanged
    If Me.OwnerItem IsNot Nothing Then
      Dim dropMenu As ToolStripMenuItem = TryCast(Me.OwnerItem, ToolStripMenuItem)
      If dropMenu IsNot Nothing Then
        AddHandler dropMenu.DropDownOpening, Sub() Me.Enabled = MagicBooleanResult()
      End If
    End If
  End Sub
End Class

答案 1 :(得分:0)

我很焦虑,但很累。醒来后我找到了解决方案,一旦我将问题中的“显示”翻译为“on paint”,确实显得很明显:

Public Class SmartMenuItem
    Inherits ToolStripMenuItem

    Public Sub New(text As String)
        MyBase.New(text)
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        Me.Enabled = MagicEnabledFunction()
        Me.Checked = MagicCheckedFunction()
        Me.Text = MagicTextFunction()

        MyBase.OnPaint(e)
    End Sub

End Class

通过重写事件处理函数(而不是使用 AddHandler Me.Paint ),您可以确保在基类处理绘制事件之前执行自定义代码,这是最佳的机会。改变显示相关属性,例如启用,选中,文本。

更新:在我的项目中使用上述技术后,我最终得到了一个基类,它消除了初始解决方案的一大缺点:快捷键仍会触发项目的点击事件,即使它已被禁用。

首先,基类:

Public Class MenuItem
    Inherits ToolStripMenuItem

    Public Delegate Sub ClickDelegate()

    Public Sub New(text As String, shortcut As Windows.Forms.Keys, clickCallback As ClickDelegate)
        MyBase.New(text)

        AddHandler Me.Click, Sub(sender As Object, e As System.EventArgs)
                                 If Me.enabledCallback Then
                                     'NOTE: shortcut keys trigger the event even, if the item is not enabled; so check here to prevent their execution
                                     clickCallback.Invoke()
                                 End If
                             End Sub


        If shortcut <> Keys.None Then
            Me.ShortcutKeys = shortcut
            Me.ShowShortcutKeys = True
        End If
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        'Store the current Enabled state before painting
        Dim _enabled As Boolean = Me.Enabled

        'Set Enabled/Checked according to the callbacks
        Me.Enabled = enabledCallback()
        Me.Checked = checkedCallback()

        'Paint the item
        MyBase.OnPaint(e)

        'Restore Enabled
        Me.Enabled = _enabled


        'NOTES:
        '- If the native Enabled-property is not disabled, then the mechanism above allows the item to always respond to shortcut keys.
        '- In the lamda click handler (which is also called when a shortcut is used) the enabledCallback will be checked to verify
        '  that the clickCallback should really be executed.
        '- This way, if the criteria for enabling/disabling the item (coded in enabledCallback) change, the shortcut keys will work as expected.
        '- Otherwise the enabled state would only be refreshed on paint and, if enabledCallback() = false, then the shortcut keys could not
        '  be used (until the item is painted again).
        '- Query Me.Enabled (or MyBase.enabledCallback) within the enabledCallback override to allow for enabling/disabling regardless of
        '  the criteria coded in the callback.
        '- A similar mechanism for Checked is not implemented, assuming the property is only relevant for painting and is not queried anywhere else.


    End Sub
    Protected Overridable Function enabledCallback() As Boolean
        Return Me.Enabled
    End Function

    Protected Overridable Function checkedCallback() As Boolean
        Return Me.Checked
    End Function
End Class

第二,派生类:

Public Class SelectionMenuItem
    Inherits Wd.Menu.MenuItem

    Public Sub New(text As String, shortCut As Windows.Forms.Keys, callback As MenuItem.ClickDelegate, minCount As Integer, Optional maxCount As Integer = 1000)
        MyBase.New(text, shortCut, callback)

        _minCount = minCount
        _maxCount = maxCount
    End Sub

    Private _minCount As Integer
    Private _maxCount As Integer

    Protected Overrides Function enabledCallback() As Boolean
        Return (Magic.Selection.Count >= _minCount) AndAlso (Magic.Selection.Count <= _maxCount)
    End Function
End Class

我希望上面代码中包含的评论有助于解释我如何解决这个问题;现在还没有时间详细说明; o)