A Toolbar of Your Favorite Menu Items? Interesting…

Originally posted at SOAPitStop.com – Sept 2, 2009

Remember that little idea that Office had a while ago that would hide infrequently-used menu items?  Wasn’t that a great idea?  For me, it was the very first thing I turned off after installing Office.  But I do understand what they were going after.  When applications do so much, every user is probably just using a subset of the whole application’s features.

The application that I’m writing is kind of getting like that.  A few versions ago, I created a toolbar on the side that was planned to be context-sensitive, so it would show actions based on what data was shown and available – kind of how Microsoft is now doing with the task pane.  Eventually, I may create or convert the toolbar to a task pane.  But as the application was growing, I had the same thought the Office designers had: each user probably only cares about 5 or 6 menu items at a time and those items should be as readily available as possible.  So instead of making personalized menus, I decided to create a Favorites toolbar.  This is similar to Microsoft programs where you can add toolbars and put menu items on them.

Because the application is in flux and because I am lazy, I didn’t want to go through the effort of creating a “Customize Toolbar” dialog.  I also didn’t want to have an extra dialog for “Add To Favorites”.  So what I did was allow menu items to be dragged onto the toolbar.  The proof-of-concept started as most do, just to see how it would work.  I got it going in under 150 lines of code, even less considering whitespace and definitions and all.

To quickly summarize the technique, I started by putting a toolbar container on the form, adding a toolstrip to hold the favorites, and adding a menu to hold the draggable items.

Then I added the code to allow the dragging of the menu items:

    Private Sub Menu_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) _
        Handles mnuFirst.MouseMove, mnuSecond.MouseMove, mnuThird.MouseMove, mnuFourth.MouseMove, _
        mnu2ndLevel1.MouseMove, mnu2ndLevel2.MouseMove, mnu2ndLevel3.MouseMove

        Dim item As ToolStripMenuItem

        If e.Button = Windows.Forms.MouseButtons.Left Then
            item = CType(sender, ToolStripMenuItem)
            item.DoDragDrop(item, DragDropEffects.Copy)
        End If

    End Sub

Then the code to drop the items (the toolstrip needs to have AllowDrop set to True):

    Private Sub toolFavorites_DragEnter(ByVal sender As Object, ByVal e As DragEventArgs) _
        Handles toolFavorites.DragEnter

        If e.AllowedEffect = DragDropEffects.Copy AndAlso e.Data.GetDataPresent(GetType(ToolStripItem)) Then
            e.Effect = DragDropEffects.Copy
        End If

    End Sub

    Private Sub toolFavorites_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) _
        Handles toolFavorites.DragDrop

        Dim droppedItem As ToolStripItem

        droppedItem = CType(e.Data.GetData(GetType(ToolStripItem)), ToolStripItem)
        AddToFavorites(droppedItem)

    End Sub

    Private Sub AddToFavorites(ByVal item As ToolStripItem)
        Dim newItem As ToolStripButton

        newItem = New ToolStripButton(item.Text, item.Image)
        newItem.Tag = item
        AddHandler newItem.MouseDown, AddressOf FavoritesContext
        AddHandler newItem.Click, AddressOf FavoritesClick
        AddHandler item.EnabledChanged, AddressOf OnMenuEnabledChanged

        toolFavorites.Items.Add(newItem)

    End Sub

Then the code to route the click of the favorites to the real menu item

    Private Sub FavoritesClick(ByVal s As Object, ByVal e As EventArgs)
        Dim item As ToolStripItem

        item = CType(CType(s, ToolStripItem).Tag, ToolStripMenuItem)
        item.PerformClick()

    End Sub

That was really it.  Of course, then I had to persist the favorites in My.Settings and provide a way of removing the favorite menu item, resulting in the above-referenced AddHandler statement for FavoritesContext and a couple other methods for running through the menu items on the form load and close.  Then we need to disable the favorite button when the linked menu item is disabled, leading to the AddHandler for OnMenuEnabledChanged.  It just keeps growing.