Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Add Most Recently Used Files (MRU) List to Windows Applications

0.00/5 (No votes)
26 Nov 2012 1  
A .NET4.0 alternative for Add Most Recently Used Files (MRU) List to Windows Applications

Introduction

I've written applications in the past in which users need to open files and have found that they usually re-open the same files over and over. So instead of forcing them to browse and open the same file over and over again, I decided to create an MRUManager, to make things easier.

Background

It uses the Windows Registry to store the paths of the recently opened files, so if you're not familiar with the registry, Wikipedia would be a good place to start. As a reference, use Microsoft's documentation of the C# class Microsoft.Win32.Registry if you're unsure about the registry manipulation methods.

Using the Code

You can use the MRUManager class right away (at your own risk, of course) without having to modify the code. There are only a few requirements.

void myOwnRecentFileGotClicked_handler(void obj, EventArgs evt)  

This method will be called when the user clicks on one of the recent items.

  1. Using Visual Studio, create a ToolStripMenuItem to be used as the parent menu item of the recent files list. Don't put sub-menu items in this one as they will be removed by the MRUManager.
  2. Create a method with this prototype.
  3. Optional: create a method that has the same parameters as the previous one. This will be called after a user clicks 'Clear list'.

Once you have those, simply create a new instance of the MRUManager class, like so:

private MRUManager mruManager;
 
private void Form1_Load(object sender, EventArgs e)
{
    this.mruManager = new MRUManager(
    //the menu item that will contain the recent files
    this.recentFilesToolStripMenuItem, 
 
    //the name of your program
    "myProgram",
    
    //the function that will be called when a recent file gets clicked.
    this.myOwn_recentFileGotClicked_handler, 
    
    //an optional function to call when the user clears the list of recent items
    this.myOwn_recentFilesGotCleared_handler);
}

Afterwards, there are two public methods that can be called:

public void AddRecentFile(string fileNameWithFullPath)
public void RemoveRecentFile(string fileNameWithFullPath) 

Examples of their usage:

private void openToolStripMenuItem_Click(object obj, EventArgs evt)
{
    FileDialog openFileDlg = new OpenFileDialog();
    openFileDlg.InitialDirectory = Environment.CurrentDirectory;
    if(openFileDlg.ShowDialog() != DialogResult.OK)
        return;
    string openedFile = openFileDlg.FileName;
    
    //Now give it to the MRUManager
    this.mruManager.AddRecentFile(openedFile);
 
    //do something with the file here
    MessageBox.Show("Through the 'Open' menu item, you opened: " + openedFile);
}
private void myOwn_recentFileGotClicked_handler(object obj, EventArgs evt)
{
    string fName = (obj as ToolStripItem).Text;
    if (!File.Exists(fName))
    {
        if (MessageBox.Show(string.Format("{0} doesn't exist. Remove from recent " + 
                 "workspaces?", fName), "File not found", 
                 MessageBoxButtons.YesNo) == DialogResult.Yes)
            this.mruManager.RemoveRecentFile(fName);
        return;
    }
    
    //do something with the file here
    MessageBox.Show(string.Format("Through the 'Recent Files' menu item, you opened: {0}", fName));
}
  1. If a user opens (or even saves) a file
  2. When the user clicks on a recent file, but it doesn't exist

Inside the Class

Below is an overall view of the class:

public class MRUManager
{
    private string NameOfProgram;
    private string SubKeyName;
    private ToolStripMenuItem ParentMenuItem;
    private Action<object, EventArgs> OnRecentFileClick;
    private Action<object, EventArgs> OnClearRecentFilesClick;
 
    private void _onClearRecentFiles_Click(object obj, EventArgs evt)
    private void _refreshRecentFilesMenu()
    
    public void AddRecentFile(string fileNameWithFullPath)
    public void RemoveRecentFile(string fileNameWithFullPath)
    
    public MRUManager(
        ToolStripMenuItem parentMenuItem,
        string nameOfProgram,
        Action<object, EventArgs> onRecentFileClick,
        Action<object, EventArgs> onClearRecentFilesClick = null
    )
}

There are two private methods that do some of the work for the class: _refreshRecentFilesMenu() and _onClearRecentFiles_Click().

When a new MRUManager object is instantiated, the constructor checks for invalid parameters. If there are any, it throws a new ArgumentException. It then calls _refreshRecentFilesMenu() to update the list, in case there were any entries previously stored in the registry.

The registry key that the class stores recent files under is "HKEY_CURRENT_USER\SOFTWARE\{program name that you supplied}\MRU". It stores this string in a private member, SubKeyName.

Whenever you call AddRecentFile(), it creates a new value under that key. Value names are numerical and go from 0 to as many as you add. It then calls _refreshRecentFilesMenu().

Whenever you call RemoveRecentFile(), it searches for a value under SubKeyName that contains the file name that you pass in and deletes it. It then calls _refreshRecentFilesMenu().

_refreshRecentFilesMenu() calls {ToolStripMenuItem that you supplied}.DropDownItems.Clear() and then repopulates it with all the values in the registry. Each recent file menu item that it adds gets passed an EventHandler that points to the function that you supplied. It then adds two items: a separator and 'Clear list' menu item, which, when clicked, runs the private method _onClearRecentFiles_Click().

_onClearRecentFiles_Click() does three things: clears the registry of recent files, clears the menu item and calls the function that the user may have optionally specified.

Simplified versions of _refreshRecentFilesMenu() and _onClearRecentFiles_Click() are shown below:

private void _refreshRecentFilesMenu()
{
    string s;
    ToolStripItem tSI;
    RegistryKey rK = Registry.CurrentUser.OpenSubKey(this.SubKeyName, false);
 
    this.ParentMenuItem.DropDownItems.Clear();
    string[] valueNames = rK.GetValueNames();
    foreach (string valueName in valueNames)
    {
        s = rK.GetValue(valueName, null) as string;
        if (s == null)
            continue;
        tSI = this.ParentMenuItem.DropDownItems.Add(s);
        tSI.Click += new EventHandler(this.OnRecentFileClick);
    }
 
    if (this.ParentMenuItem.DropDownItems.Count == 0)
    {
    this.ParentMenuItem.Enabled = false;
        return;
    }
 
    this.ParentMenuItem.DropDownItems.Add("-");
    tSI = this.ParentMenuItem.DropDownItems.Add("Clear list");
    tSI.Click += new EventHandler(this._onClearRecentFiles_Click);
    this.ParentMenuItem.Enabled = true;
}  
private void _onClearRecentFiles_Click_SIMPLIFIED(object obj, EventArgs evt)
{
    RegistryKey rK = Registry.CurrentUser.OpenSubKey(this.SubKeyName, true);
    if (rK == null)
        return;
    string[] values = rK.GetValueNames();
    foreach (string valueName in values)
        rK.DeleteValue(valueName, true);
    rK.Close();
    this.ParentMenuItem.DropDownItems.Clear();
    this.ParentMenuItem.Enabled = false;
    
    if (OnClearRecentFilesClick != null)
        this.OnClearRecentFilesClick(obj, evt);
}

Deviations from the Original Article

Although the MRUManager class in this article was written from scratch, it bears a resemblance to the original article's implementation. For example, it still uses the registry to store file paths and the GUI interface it creates is much like the original. I decided to make my MRUManager more minimalistic, by not including things like 'maxNumberOfFiles' or 'maxDisplayLength', yet still functional enough to use right away.

History

  • June 19, 2012 - Article created
  • June 20, 2012 - Article changed as an alternative
  • November 20, 2012 - Bug fix: RemoveRecentFile() not properly removing files from list

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