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)
6 Feb 2003 1  
Provides an implementation for and teaches you how to add a list of most recently used files to your Windows Forms applications.

Sample Image

Introduction

The Most Recently Used (MRU) files list is standard feature of most Windows applications. This article describes how to add MRU support to Windows application using the class MRUManager. This class is included in the demo project. It may be added to your C# project or compiled in DLL and used by developers working with any .NET language. While writing this class I tried to reproduce MFC's CRecentFileList class behaviour.

Using the MRUManager Class

The starting point is a simple image viewer application which has File - Open menu and shows an image file in the form's client area. When user selects the Open menu item, the program shows the Open File dialog:

private void mnuFileOpen_Click(object sender, System.EventArgs e)
{
    OpenFileDialog openDlg = new OpenFileDialog();
    openDlg.Filter  = "Jpeg files (*.jpg)|*.jpg|Bitmap files (*.bmp)|*.bmp|All Files (*.*)|*.*";

    openDlg.FileName = "" ;
    openDlg.CheckFileExists = true;
    openDlg.CheckPathExists = true;

    if ( openDlg.ShowDialog() != DialogResult.OK )
        return;

    OpenFile(openDlg.FileName);
}

The method OpenFile loads the image file into the class member Bitmap bitmap, and the Paint event handler shows this bitmap on the screen:

private Bitmap bitmap;

private void OpenFile(string fileName)
{
    Bitmap bmp;

    try
    {
        bmp = (Bitmap)Bitmap.FromFile(fileName, false);

        if ( bmp != null )
        {
            bitmap = (Bitmap) bmp.Clone();

            this.AutoScroll = true;
            this.AutoScrollMinSize = new Size (bitmap.Width, bitmap.Height);
            
            Invalidate();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(this, ex.Message, "Error loading from file");
    }
}

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    if ( bitmap != null )
    {
        e.Graphics.DrawImage(
            bitmap, 
            new Rectangle(this.AutoScrollPosition.X, 
            this.AutoScrollPosition.Y, 
            bitmap.Width, 
            bitmap.Height));
    }
}

To add MRU support to this application, we need to take the following steps:

1. Add a Recent Files menu item to the application menu:


Sample Image

In the demo project this item is called mnuFileMRU.

2. Implement IMRUClient interface in the form. This interface is defined in the same file as MRUManager:

public interface IMRUClient
{
    void OpenMRUFile(string fileName);
}

Implementation:

public class Form1 : System.Windows.Forms.Form, IMRUClient
{
    public void OpenMRUFile(string fileName)
    {
        OpenFile(fileName);
    }
    
    // ...

}

3. Add an MRUManager member to the form class and initialize it:

private MRUManager mruManager;

private void Form1_Load(object sender, System.EventArgs e)
{
    mruManager = new MRUManager();
    mruManager.Initialize(this, mnuFileMRU, registryPath);

    // Optional:

    // mruManager.CurrentDir = ".....";        // default is current directory

    // mruManager.MaxMRULength = ...;          // default 10

    // mruMamager.MaxDisplayNameLength = ...;  // default 40

}

MRUManager is initialized with a reference to the owner form, Recent Files menu item and registry path to store the MRU. If the registry path is, for example, "Software\MyCompany\MyProgram", the MRU list is stored in the HKEY_CURRENT_USER\Software\MyCompany\MyProgram\MRU registry entry.

Additional properties (CurrentDir, MaxMRULength, MaxDisplayNameLength) may be optionally changed.

  • CurrentDir - the default value is the program's current directory at the time when the Initialize method is called. Files in this directory are shown in the menu without a path.
  • MaxMRULength - the default value is 10. This is the maximum number of files stored in MRU list.
  • MaxDisplayNameLength - the default value is 40. Long file names are truncated to this length in the menu.

4. Call MRUManager.Add() and Remove methods when necessary:

private void OpenFile(string fileName)
{
    Bitmap bmp;

    try
    {
        // ...


        // add successfully opened file to MRU list

        mruManager.Add(fileName);
    }
    catch (Exception ex)
    {
        // remove file from MRU list

        mruManager.Remove(fileName);

        // ...

    }

}

Add is called when file is open successfully. Remove is called when Open method failed.

The program is ready. Run it and see how it works. When the program runs the first time and the MRU list is empty, the Recent Files menu item is disabled. When the file is opened, its name is added to the MRU list. If a user opens the file which is already in the MRU list, the file name is moved to the first position.

The MRUManager Class Implementation

The class has the following members:

private Form ownerForm;                 // owner form

private MenuItem menuItemMRU;           // Recent Files menu item

private MenuItem menuItemParent;        // Recent Files menu item parent

private string registryPath;            // Registry path to keep MRU list

private int maxNumberOfFiles = 10;      // maximum number of files in MRU list

private int maxDisplayLength = 40;      // maximum length of file name for display

private string currentDirectory;        // current directory

private ArrayList mruList;              // MRU list (file names)

private const string regEntryName = "file";  // entry name to keep MRU (file0, file1...)

The Initialize method fills class members and subscribes to the Recent Files parent's Popup and owner form's Closing events:

public void Initialize(Form owner, MenuItem mruItem, string regPath)
{
    ownerForm = owner;

    // check if owner form implements IMRUClient interface

    if ( ! ( owner is IMRUClient ) )
    {
        throw new Exception("MRUManager: Owner form doesn't implement IMRUClient interface");
    }

    // keep reference to MRU menu item

    menuItemMRU = mruItem;

    // keep reference to MRU menu item parent

    try
    {
        menuItemParent = (MenuItem) menuItemMRU.Parent;
    }
    catch
    {
    }

    if ( menuItemParent == null )
    {
        throw new Exception("MRUManager: Cannot find parent of MRU menu item");
    }

    // keep Registry path adding MRU key to it

    registryPath = regPath;
    if ( registryPath.EndsWith("\\") )
         registryPath += "MRU";
    else
        registryPath += "\\MRU";

    // keep current directory in the time of initialization
    currentDirectory = Directory.GetCurrentDirectory();

    // subscribe to MRU parent Popup event
    menuItemParent.Popup += new EventHandler(this.OnMRUParentPopup);

    // subscribe to owner form Closing event
    ownerForm.Closing += new System.ComponentModel.CancelEventHandler(OnOwnerClosing);

    // load MRU list from Registry
    LoadMRU();
}

The LoadMRU method reads the MRU list from registry. The OnOwnerClosing method is called when the owner form is closed and saves the MRU list to the registry.

OnMRUParentPopup is called when the Recent Files menu item parent is opened. This method fills the MRU menu list:

private void OnMRUParentPopup(object sender, EventArgs e)
{
    // remove all childs

    if ( menuItemMRU.IsParent )
        menuItemMRU.MenuItems.Clear();
 
    // Disable menu item if MRU list is empty

    if ( mruList.Count == 0 )
    {
        menuItemMRU.Enabled = false;
        return;
    }

    // enable menu item and add child items

    menuItemMRU.Enabled = true;

    MenuItem item;
    IEnumerator myEnumerator = mruList.GetEnumerator();

    while ( myEnumerator.MoveNext() )
    {
        item = new MenuItem(GetDisplayName((string)myEnumerator.Current));

        // subscribe to item's Click event

        item.Click += new EventHandler(this.OnMRUClicked);

        menuItemMRU.MenuItems.Add(item);
    }
}

The GetDisplayName method gets the short file name from the full file name. If the file is in the current directory, it is shown without a path. The file name is also truncated to the maximum allowed length using the Shell API's PathCompactPathEx function (thanks to CodeProject and GotDotNet C# expert Richard Deeming for this solution).

The OnMRUClicked method is called when the user clicks selects one of the MRU menu items. It calls the owner form's OpenMRUFile method:

private void OnMRUClicked(object sender, EventArgs e)
{
    string s;

    try
    {
        MenuItem item = (MenuItem) sender;

        if ( item != null )
        {
            s = (string)mruList[item.Index];

            // call owner's OpenMRUFile function

            if ( s.Length > 0 )
            {
                ((IMRUClient)ownerForm).OpenMRUFile(s);
            }
        }
    }
    catch ( Exception ex )
    {
        Trace.WriteLine("Exception in OnMRUClicked: " + ex.Message);
    }
}

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