65.9K
CodeProject 正在变化。 阅读更多。
Home

向Windows应用程序添加最近使用文件(MRU)列表

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2012年6月20日

CPOL

3分钟阅读

viewsIcon

52619

downloadIcon

1915

一种适用于 "将最近使用文件 (MRU) 列表添加到 Windows 应用程序" 的 .NET4.0 替代方案

引言

我过去编写的应用程序中,用户需要打开文件,我发现他们通常会反复重新打开相同的文件。因此,为了避免他们反复浏览和打开相同的文件,我决定创建一个 MRUManager,以使事情更简单。

背景

它使用 Windows 注册表来存储最近打开文件的路径,因此如果您不熟悉注册表,维基百科 将是一个很好的起点。作为参考,如果您不确定注册表操作方法,请使用微软的 C# 类文档 Microsoft.Win32.Registry

Using the Code

您可以立即使用 MRUManager 类(当然,风险自负),而无需修改代码。只有几个要求。

void myOwnRecentFileGotClicked_handler(void obj, EventArgs evt)  

当用户单击最近的项目之一时,将调用此方法。

  1. 使用 Visual Studio,创建一个 ToolStripMenuItem 作为最近文件列表的父菜单项。不要在此项中放置子菜单项,因为它们将被 MRUManager 删除。
  2. 创建一个具有此原型的方​​法。
  3. 可选:创建一个具有与上一个方法相同参数的方法。这将在用户单击“清除列表”后调用。

一旦你拥有了这些,只需创建一个 MRUManager 类的新实例,像这样

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);
}

之后,有两个 public 方法可以调用

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

它们的使用示例

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. 如果用户打开(甚至保存)一个文件
  2. 当用户单击最近的文件,但它不存在时

在类里面

下面是该类的整体视图

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
    )
}

有两个 private 方法用于完成该类的一些工作:_refreshRecentFilesMenu()_onClearRecentFiles_Click()

实例化一个新的 MRUManager 对象时,构造函数会检查无效参数。如果有任何参数,它将抛出一个新的 ArgumentException。然后它调用 _refreshRecentFilesMenu() 以更新列表,以防之前在注册表中存储任何条目。

该类存储最近文件的注册表项是 "HKEY_CURRENT_USER\SOFTWARE\{您提供的程序名称}\MRU"。它将此 string 存储在 private 成员 SubKeyName 中。

每当您调用 AddRecentFile() 时,它都会在该键下创建一个新值。值名称是数字的,从 0 到您添加的任意数量。然后它调用 _refreshRecentFilesMenu()

每当您调用 RemoveRecentFile() 时,它会搜索 SubKeyName 下包含您传入的文件名的值并将其删除。然后它调用 _refreshRecentFilesMenu()

_refreshRecentFilesMenu() 调用 {您提供的 ToolStripMenuItem}.DropDownItems.Clear() 然后使用注册表中的所有值重新填充它。它添加的每个最近的文件菜单项都会获得一个指向您提供函数的 EventHandler。然后它添加两个项目:一个分隔符和一个“清除列表”菜单项,单击该菜单项将运行 private 方法 _onClearRecentFiles_Click()

_onClearRecentFiles_Click() 做三件事:清除注册表中最近的文件、清除菜单项并调用用户可能已选择指定的功能。

下面显示了 _refreshRecentFilesMenu()_onClearRecentFiles_Click() 的简化版本

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);
}

与原始文章的偏差

尽管本文中的 MRUManager 类是从头开始编写的,但它与原始文章的实现相似。例如,它仍然使用注册表来存储文件路径,并且它创建的 GUI 界面与原始文章非常相似。我决定让我的 MRUManager 更简约,例如,不包含像“maxNumberOfFiles”或“maxDisplayLength”之类的东西,但仍然足够实用,可以立即使用。

历史

  • 2012 年 6 月 19 日 - 文章创建
  • 2012 年 6 月 20 日 - 文章更改为替代方案
  • 2012 年 11 月 20 日 - 错误修复:RemoveRecentFile() 未正确从列表中删除文件
© . All rights reserved.