Creating a Most Recents Menu Item with the MenuStrip, Page 2
The last bit is the RecentsClick that responds when you click on the new dynamic menu. The code does a simple sanity check to see whether the sender is a ToolStripMenuItem. (You could safely skip that check here because your code is doing the wire-up of the event, so you know it's a ToolStripMenuItem. By the way, this form of the If conditional is called a sentinel; it's shorter and sweeter than an If Then End If, but does result in multiple exit points.) Finally, you reuse OpenFile, which is exactly why you use named methods rather than writing all code directly in the event handler itself.
Of course, you don't have to agree with me on style, but my style for me is a very fast way to program. It reduces superfluous comments, and promotes reuse.
Refactoring the Code into a Command Class
Now, in all but trivial samples I might start with code like Listing 1 (probably not, but I might). What I would end up with, though, is a Command class for the Open File with Recents behavior embedded in it. Why? Good question. Encapsulating this behavior in a class means it's portable at the class level, it keeps my Form code simpler, and it promotes reuse in other ways. For example, with a Command class I could add new ways to invoke the behavior like through a button, a wizard, auto-pilot mode, or perhaps as a controllable API (think OLE Automation-type control).
Listing 2 shows the Form code Refactored. The code, combined with Listing 3, does the same thing but now most of the behaviors are moved to an external command class.
Listing 2: Form1 revised to use a Command class.
Imports System.IO Imports System.Diagnostics Public Class Form1 Private _openFileCommand As OpenFileCommand Private Sub OpenToolStripMenuItem_Click(ByVal sender _ As System.Object, _ ByVal e As System.EventArgs) _ Handles OpenToolStripMenuItem.Click _openFileCommand._Do() End Sub Private Function OpenFile(ByVal filename As String) As Integer Debug.Assert(File.Exists(filename)) Dim data As String = File.ReadAllText(filename) TextBox1.Text = data.Replace("\r", " ") Return 0 End Function Private Sub FileOK(ByVal sender As Object, _ ByVal e As FileEventArgs) OpenFile(e.FileName) End Sub Private Sub Form1_Load(ByVal sender _ As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load _openFileCommand = New OpenFileCommand() AddHandler _openFileCommand.FileOKClick, AddressOf FileOK AddHandler _openFileCommand.RecentsClicked, AddressOf FileOK _openFileCommand.RecentsMenu = RecentFilesToolStripMenuItem End Sub End Class
The two things that happen in the new form are the initialization of the command object with event wire-ups and the OpenFile method and that is it. Listing 3 contains the command class.
Listing 3: The OpenFileCommand now contains all of the orchestration among opening a file, signaling the Command class consumer, and populating the Recent Files menu.
Imports System.IO Imports System.Diagnostics Imports System.Windows.Forms Public Class FileEventArgs Inherits EventArgs Public Sub New(filename As String) MyBase.New() _fileName = filename End Sub Private _fileName As String Public Property FileName() As String Get Return _fileName End Get Set(ByVal Value As String) _fileName = Value End Set End Property End Class Public Class OpenFileCommand Private _openFileDialog As OpenFileDialog Public Sub New() _openFileDialog = New OpenFileDialog() AddHandler _openFileDialog.FileOk, AddressOf FileOK End Sub Private Sub FileOK(ByVal sender As Object, ByVal e As EventArgs) RaiseEvent FileOKClick(Me, _ New FileEventArgs(_openFileDialog.FileName)) AddToRecents() End Sub Private Sub AddToRecents() If (_recentsMenu Is Nothing) Then Return Dim menu As ToolStripMenuItem = _ _recentsMenu.DropDownItems.Add(_openFileDialog.FileName) AddHandler menu.Click, AddressOf RecentsClick End Sub Private Sub RecentsClick(ByVal sender As Object, ByVal e As EventArgs) RaiseEvent RecentsClicked(Me, _ New FileEventArgs(DirectCast(sender, _ ToolStripMenuItem).Text)) End Sub Public Event RecentsClicked As EventHandler(Of FileEventArgs) Public Event FileOKClick As EventHandler(Of FileEventArgs) Private _initialDirectory As String = "C:\TEMP" Public Property InitialDirectory() As String Get Return _initialDirectory End Get Set(ByVal Value As String) _initialDirectory = Value End Set End Property Private _filter As String = "Text Files (*.txt)|*.txt" Public Property Filter() As String Get Return _filter End Get Set(ByVal Value As String) _filter = Value End Set End Property Private _title As String = "Open File" Public Property Title() As String Get Return _title End Get Set(ByVal Value As String) _title = Value End Set End Property Private _recentsMenu As ToolStripMenuItem Public Property RecentsMenu() As ToolStripMenuItem Get Return _recentsMenu End Get Set(ByVal Value As ToolStripMenuItem) _recentsMenu = Value End Set End Property Public Sub _Do() _openFileDialog.InitialDirectory = _initialDirectory _openFileDialog.Filter = _filter _openFileDialog.Title = _title _openFileDialog.ShowDialog() End Sub Public Sub Undo() End Sub End Class
