Click here to Skip to main content
Click here to Skip to main content

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

, 26 Nov 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
A .NET4.0 alternative for "Add Most Recently Used Files (MRU) List to Windows Applications"

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.  

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.

  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. void myOwnRecentFileGotClicked_handler(void obj, EventArgs evt)  

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

  4. 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 funtion 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:

  1. If a user opens (or even saves) a file:
  2. 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);
    }
  3. When the user clicks on a recent file, but it doesn't exist.
  4. 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));
    }

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 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. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Adib Saad

Canada Canada
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberkarthikin30-Jul-12 1:24 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.141029.1 | Last Updated 26 Nov 2012
Article Copyright 2012 by Adib Saad
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid