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.
I wanted to keep the post short, so if you’re interesting in these other pieces, I put a ZIP of the POC source at http://www.700cb.net/Downloads/DragMenus.zip. That something I usually don’t do. Interesting…