-1

网上有几个关于如何禁用菜单项的项的示例(例如,使用parent的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属性当然是相同的交易......

4

2 回答 2

0

我很着急,但也很累。醒来后,我找到了解决方案,一旦我将问题中的“显示”一词翻译为“油漆上”,这确实显得很明显:

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)

于 2015-02-06T09:13:54.893 回答
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
于 2015-02-06T01:03:56.417 回答