Click here to Skip to main content
15,881,248 members
Articles / Programming Languages / C#
Article

Most Recently Used (MRU) Menu Class in C#

Rate me:
Please Sign up or sign in to vote.
4.29/5 (26 votes)
13 Nov 20077 min read 143.2K   2.9K   63   26
A Most Recently Used files class, in C#.
Sample Image

Non-Maintenance Notice

This code will no longer be maintained. It is only by luck that I still happen to have Visual Studio 2003 installed and was able to test the latest changes. I will leave the article on Code Project just in case someone needs this code.

Introduction

As I've been teaching myself C#.NET, I've quickly learned it lacks many of the UI oriented features I've grown accustomed to with MFC. One glaring omission is the lack of the most recently used (MRU) file list functionality from the menu class. This class presents a stop-gap solution until Microsoft adds an integrated one to the menu classes and the .NET Framework.

A Visual Studio 2005 / .NET 2.0 version of this class has been created. The new article can be found here.

The MruMenu Class

The MruMenu class displays a list of most recently used files in a popup menu. A derived class, MruMenuInline, displays them as additional entries in a menu, or inline. In both cases, a number is displayed to the left of the file. Entries 1-10 allow you to use a number on the keyboard to select that entry.

Namespace

This class is in them oh so creatively named, JWC (Joe Woodbury Classes) namespace.

Constructors

C#
MruMenu(MenuItem recentFileMenuItem, ClickedHandler clickedHandler)
MruMenu(MenuItem recentFileMenuItem, ClickedHandler clickedHandler, 
                                                     int maxEntries)
MruMenu(MenuItem recentFileMenuItem, ClickedHandler clickedHandler, 
                                             String registryKeyName)
MruMenu(MenuItem recentFileMenuItem, ClickedHandler clickedHandler, 
                             String registryKeyName, int maxEntries)
MruMenu(MenuItem recentFileMenuItem, ClickedHandler clickedHandler, 
                      String registryKeyName, bool loadFromRegistry)
MruMenu(MenuItem recentFileMenuItem, ClickedHandler clickedHandler, 
      String registryKeyName, bool loadFromRegistry, int maxEntries)

recentFileMenuItem

This is the menu item that will serve as the anchor point for the MRU list. It must be created and inserted into the desired spot in a menu, before creating an MruMenu instance.

clickedHandler

The delegate that will be called when one of the MRU entries is selected. The entry number (zero based) and the filename will be passed to the handler.

registryKeyName

The name of a registry key MruMenu will use to load and/or store the contents of the MRU list. If a key name is passed to the constructor, and loadFromRegistry is true, MruMenu will attempt to load the files from the registry. However, to save the MRU list, you must call SaveToRegistry().

loadFromRegistry

If true, MruMenu will attempt to load the MRU list stored in the passed registry key. If the registry key does not exist, an exception will not be thrown.

maxEntries

The maximum number of entries to allow in the MRU list. Currently, for practical reasons, the number of entries is limited to be from 4 through 16. If _maxEntries is not within this range, it will be adjusted up, or down, whichever is appropriate (an ArgumentOutOfRangeException will not be thrown.)

Delegates

C#
public delegate void ClickedHandler(int number, String filename)
  • number - The MRU relative number of the entry that was clicked
  • filename - The filename of the entry that was clicked

Properties

C#
Menu.MenuItemCollection MenuItems (ReadOnly)

The MenuItemCollection where the MRU list is located.

C#
int StartIndex (ReadOnly)

The menu index of the first MRU entry.

C#
int EndIndex (ReadOnly)

The menu index immediately "after" the last MRU entry.

C#
int NumEntries (ReadOnly) 

The current number of MRU entries.

C#
int MaxEntries (Read/Write)

The maximum number of MRU entries allowed. You can set the MaxEntries to the range of 4 through 16. If the new maximum entries is less than the current number of entries, the oldest entries will be discarded.

C#
int MaxShortenPathLength (Read/Write)

The maximum length of the path to allow in the menu, in characters. When setting, any value less than 16 will be changed to 16. The new length will have no effect on the current contents of the menu.

C#
String RegistryKeyName (Read/Write)

Set/Get the registry key name where MRU list will be loaded/saved. No error checking is done to verify if the key is valid.

Static Methods

C#
static String FixupEntryname(int number, String entryname)

Adds the entry number prefix and mnemonic (for entries 0-9) to the filename. Note that the number is zero based, while the actually displayed numbering is one based.

  • number

    The MRU relative number to use for the prefix.

  • entryname

    The string to which to apply the prefix.

C#
static String ShortenPathname(String pathname, int maxLength)

If the pathname is longer than maxLength, it replaces consecutive path components ellipsis. It will always preserve the root of the path and at least three characters of the filename, which may cause the result to be longer than maxLength.)

  • pathname

    The pathname to check and, possibly, shorten. The pathname should be fully resolved and start with a drive letter or be a UNC path.

  • maxLength

    The maximum length, in characters, of the resulting path.

Methods

C#
int FindFilenameNumber(String filename)

Find the MRU relative number of the entry which matches filename. This match must be exact except for case sensitivity.

Returns -1 if a matching entry cannot be found.

  • filename

    The filename to find.

C#
int FindFilenameMenuIndex(String filename)

Find the menu index of the entry which matches filename. This match must be exact except for case sensitivity.

Returns -1 if a matching entry cannot be found

  • filename

    The filename to find.

C#
int GetMenuIndex(int number)

Returns the menu index of the entry at the MRU relative number.

  • number

    The MRU relative number of the menu index.

C#
String GetFileAt(int number)

Return the filename stored at the MRU relative number.

  • number

    The MRU relative number of the filename to remove. Note that this number is zero based, while the display is one based.

C#
String[] GetFiles()

Returns the list of files in the MRU list. The most recent file will be at index zero.

C#
void SetFiles(String[] filenames)

Replaces the MRU entries with filenames. (Functionally equivalent to: RemoveAll(); AddFiles(filenames);) The filenames will be added such that the first string in the array will be topmost on the MRU list. (In other words, the entries will be added from the end to the beginning.)

  • filenames

    The list of filenames to set.

C#
void SetFirstFile(int number)

Makes the specified entry the first on the MRU list.

  • number

    The MRU relative number of the entry to make the first. Note that this number is zero based, while the display is one based.

C#
void AddFiles(String[] filenames)

Adds filenames to the list of files. The filenames will be added such that the first string in the array will be topmost on the MRU list. (In other words, the entries will be added from the end to the beginning.)

  • filenames

    The list of filenames to add.

C#
void AddFile(String filename)

Adds a filename to the MRU list. If the entry exists, it will be moved to the first position. Otherwise it will be added in the first position. If the number of entries exceeds maxEntries, the least recent file (the last one) will be removed.

Before being added, the filename will first be resolved to an absolute path. The result will then be passed to the ShortenPathname function. Despite the absolute path resolution, it is possible for multiple entries to refer to the same physical file.

  • filename

    The filename to add.

C#
void AddFile(String filename, String entryname)

Adds entryname to the MRU list and stores filename with that entry. If the entry exists, it will be moved to the first position. Otherwise it will be added in the first position. If the number of entries exceeds maxEntries, the least recent file (the last one) will be removed. Note that filename will be used to determine whether an entry exists. Thus it is possible to have two identical entries in the MRU list, even though the associated filenames are different.

  • filename

    The filename to add.

  • entryname

    The text to use in the MRU menu.

C#
void RemoveFile(int number) 

Removes the entry at the MRU relative number.

  • number

    The MRU relative number of the entry to remove. Note that this number is zero based, while the display is one based.

C#
void RemoveFile(String filename)

Removes the entry associated with filename.

  • filename

    The filename to remove.

C#
void RemoveAll()

Removes all MRU entries.

C#
void LoadFromRegistry(String keyName) 

Sets the registry key and loads the entries located at that key.

  • keyName

    The registry key from which to restore the MRU entries.

C#
void LoadFromRegistry()

Loads the entries located at the stored key.

C#
void SaveToRegistry(String keyName)

Sets the registry key and saves the entries to that key.

  • keyName

    The registry key where the MRU entries will be stored.

C#
void SaveToRegistry() 

Saves the entries located at the stored key.

Changes

17 July 2003

  • Posted on Code Project

18 July 2003

  • Added SetFirstFile() method
  • Added code to MruMenuDemo to better demonstrate how to use MruMenu
  • Added section describing namespace

17 December 2003

  • Added an empty constructor to the internal class MruMenuItem. This prevents an exception when using the class with MDI applications.

16 October 2007

  • Fixed a bug in FixupPrefixes where the first character was being stripped (thanks to shostakovich55 for that catch and his elegant solution.)
  • Constructor now calls property to set MaxEntries which does range checking

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Joe is one of those software engineers with a film degree. His first paid programming job (you think film is a good way to make a living?) was writing games for Apple II's using 6502 assembly. He soon moved to 80x86 assembly, C, C++ (for a long time), C# and then back to C++ with occasional dabbling in C#, Python and other vile languages.

He first wrote software for Windows 3.0 in 1990. Save for some work in Linux, DOS and a mercifully brief foray into OS/2, he has concentrated on designing and writing software for all versions and types of Windows except RT.

Comments and Discussions

 
Question"Read" access problems to the menu file? Pin
chuckles_net3-Jul-18 12:43
chuckles_net3-Jul-18 12:43 
GeneralFixupPrefixes buglet Pin
shostakovich5516-Oct-07 4:20
shostakovich5516-Oct-07 4:20 
GeneralIsolated Storage Pin
snoopybb13-Jun-06 17:04
snoopybb13-Jun-06 17:04 
GeneralRe: Isolated Storage [modified] Pin
Joe Woodbury13-Jun-06 21:18
professionalJoe Woodbury13-Jun-06 21:18 
GeneralOff by one bug Pin
Alex Korchemniy3-Dec-05 8:03
Alex Korchemniy3-Dec-05 8:03 
GeneralRe: Off by one bug Pin
Joe Woodbury5-Dec-05 5:00
professionalJoe Woodbury5-Dec-05 5:00 
GeneralRe: Off by one bug Pin
Alex Korchemniy6-Dec-05 9:58
Alex Korchemniy6-Dec-05 9:58 
GeneralRe: Off by one bug Pin
Joe Woodbury6-Dec-05 11:29
professionalJoe Woodbury6-Dec-05 11:29 
GeneralVisual Studio 2005 Version Pin
Joe Woodbury23-Sep-05 5:59
professionalJoe Woodbury23-Sep-05 5:59 
GeneralVS2005 Pin
Daniel Plomp25-Jun-05 0:06
sussDaniel Plomp25-Jun-05 0:06 
GeneralI prefer XML Pin
Peter Wone29-Sep-04 2:35
Peter Wone29-Sep-04 2:35 
GeneralRe: I prefer XML Pin
Cape Town Developer13-Nov-07 19:58
Cape Town Developer13-Nov-07 19:58 
Generalvb.net version Pin
Norberto Olazabal26-Apr-04 12:28
Norberto Olazabal26-Apr-04 12:28 
Generalerror "System.MissingMethodException" Pin
pekai15-Dec-03 0:04
pekai15-Dec-03 0:04 
GeneralRe: error "System.MissingMethodException" Pin
Joe Woodbury17-Dec-03 16:36
professionalJoe Woodbury17-Dec-03 16:36 
Generalright mouse click Menu Pin
unitecsoft7-Oct-03 22:33
unitecsoft7-Oct-03 22:33 
GeneralRe: right mouse click Menu Pin
Joe Woodbury8-Oct-03 4:09
professionalJoe Woodbury8-Oct-03 4:09 
GeneralBUG: Does not work on MDI container if there are merged menus Pin
Craig Eddy2-Oct-03 5:03
Craig Eddy2-Oct-03 5:03 
GeneralRe: BUG: Does not work on MDI container if there are merged menus Pin
Joe Woodbury2-Oct-03 6:19
professionalJoe Woodbury2-Oct-03 6:19 
Thanks for the report. I've only used this class in an SDI application--I've never actually used MDI in .NET--so I don't have a ready response at this time. I'll look into it when I have some time though my initial feeling is that the fix, if possible, is going to be painful.

I'm not familiar with how merged menus work underneath, but I wonder if you have to initialize the class after the menus are merged.

Hopefully, Microsoft will add MRU support into .NET itself and make this class obsolete. My desire isn't just to save myself work, but it will make the whole thing more stable. (While griping, I'm hoping, probably in vain, that Microsoft obsoletes even more of my code; I'm getting tired of reinventing the wheel with every application.)



Joe Woodbury

When all else fails, there's always delusion.
- Conan O'Brien
GeneralRe: BUG: Does not work on MDI container if there are merged menus Pin
pekai14-Dec-03 23:47
pekai14-Dec-03 23:47 
GeneralBUG: Open FIRST file from MRU list Pin
Boris Ilijic23-Sep-03 3:38
Boris Ilijic23-Sep-03 3:38 
GeneralRe: BUG: Open FIRST file from MRU list Pin
Joe Woodbury23-Sep-03 15:30
professionalJoe Woodbury23-Sep-03 15:30 
QuestionSaveToRegistry Bug? Pin
Member 97157931-Aug-03 4:12
Member 97157931-Aug-03 4:12 
AnswerRe: SaveToRegistry Bug? Pin
Joe Woodbury31-Aug-03 7:57
professionalJoe Woodbury31-Aug-03 7:57 
GeneralDemo files missing Pin
AxelM17-Jul-03 20:41
AxelM17-Jul-03 20:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.