Dotneteers.net
All for .net, .net for all!

LearnVSXNow! #29 - VSXtraCommands Part 2 — Commands removing recent items

In the previous part (Part #28) I treated the command handling architecture of VSXtraCommands and promised that in this part I will show the background of more commands. In this article I am going to dive into the details of the Clear Recent Files and Clear recent Projects command. Just as I did in the first part, I show how these commands are implemented in PowerCommands then I treat their implementation with VSXtra.

Clear Recent Files and Projects implementation in PowerCommands

PowerCommands uses separate classes for handling a specific command. All handler classes derive from DynamicCommand and use static OnExecute methods to define the action to be executed by the command. Here is the code for Clear Recent File List command:

[Guid("5DC1F44A-F045-4E82-9A6A-D576BD672DB3")]

[DisplayName("Clear Recent File List")]

internal class ClearRecentFileListCommand : DynamicCommand

{

  public const uint cmdidClearRecentFileListCommand = 0x0F7D;

 

  public ClearRecentFileListCommand(IServiceProvider serviceProvider)

    : base(

      serviceProvider,

      OnExecute,

      new CommandID(

        typeof(ClearRecentFileListCommand).GUID,

        (int)ClearRecentFileListCommand.cmdidClearRecentFileListCommand))

  {

  }

 

  protected override bool CanExecute(OleMenuCommand command)

  {

    if (base.CanExecute(command))

    {

      using (RegistryKey rootKey = GetRecentRootKey())

      {

        if (rootKey != null)

        {

          return (rootKey.GetValueNames().Length > 0);

        }

      }

    }

 

    return false;

  }

 

  private static void OnExecute(object sender, EventArgs e)

  {

    ClearListView view = new ClearListView();

    using (RegistryKey key = GetRecentRootKey())

    {

      key.GetValueNames().ForEach(

        valueName => view.Model.ListEntries.Add(new KeyValue(valueName,

          key.GetValue(valueName).ToString())));

 

      if ((bool)view.ShowDialog())

      {

        DynamicCommand.Dte.ExecuteCommand("File.SaveAll", string.Empty);

        DeleteRecentFileList(view.Model.SelectedListEntries);

        ReEnumerateFileList();

        DTEHelper.RestartVS(DynamicCommand.Dte);

      }

    }

  }

 

  private static void DeleteRecentFileList(List<KeyValue> entriesToDelete)

  {

    // --- Method body omitted

  }

 

  private static void ReEnumerateFileList()

  {

    // --- Method body omitted

  }

 

  private static RegistryKey GetRecentRootKey()

  {

    // --- Method body omitted

  }

}

The constructor of the class uses the base initializer list to set up the command. Here the static OnExecute method is passed to the base constructor. OnExecute must be static otherwise it could not be passed. All the methods OnExecute calls also must be static to avoid unnecessary instantiation of the class.

When you look at the implementation of the Clear Recent Project List command you can see that it uses actually the same source code, the only difference is GetRecentRootKey method which accesses the registry key for recent projects.

The question is natural: should we really duplicate the logic or we can do something else?

Because OnExecute is static, we cannot define a base class for the common functionality and derive the recent list handling commands from there. Well, of course, we could refactor the logic into utility classes and using abstraction and inheritance to separate the common functionality from the specific ones.

Implementation in the VSXtra way

The VSXtra implementation uses the same way to carry out removing the unwanted entries from the list of recent files and recent projects, but requires less code. The PowerCommands implementation duplicates the logic by separating command handler classes for removing the recent files and for removing the recent projects.

Command handler inheritance

In the VSXtra implementation I wanted to avoid this duplication, so I put the common logic into an abstract command handler class and used it to derive command handler classes for the Clear Recent Files and Clear Recent Projects functions:

public partial class VSXtraCommandGroup

{

  // --- This is the abstract class for both command handler functions

  public abstract class ClearRecentListBase : CommandHandlerBase

  {

    // --- Execution logic differs only in the registry key used

    protected abstract RegistryKey RecentListKey { get; }

  }

 

  // --- Concrete command class for handling recent files

  [CommandId(CmdIDs.ClearRecentFileListCommand)]

  [DisplayName("Clear Recent Files")]

  public sealed class ClearRecentFileList : ClearRecentListBase

  {

    protected override RegistryKey RecentListKey

    {

      get { return VsRegistry.GetRecentFilesListKey(true); }

    }

  }

 

  // --- Concrete command class for handling recent projects

  [CommandId(CmdIDs.ClearRecentProjectListCommand)]

  [DisplayName("Clear Recent Projects")]

  public sealed class ClearRecentProjectList : ClearRecentListBase

  {

    protected override RegistryKey RecentListKey

    {

      get { return VsRegistry.GetRecentProjectsListKey(true); }

    }

  }

}

Please observe that I omitted the implementation details from the ClearRecentListBase class, but the ClearRecentFileList and ClearRecentProjectList classes’ full source code is shown.

The logic removing unwanted items differs only in the root registry keys used for the operation. Using the “FileMRUList” key provides the list of recently used files while the “ProjectMRUList” key allows accessing the list of recent projects. The ClearRecentListBase class reflects this concept: it defines the RecentListKey method to be overridden by derived command handler classes. The two concrete handler classes override it to access the appropriate registry key.

Using VSXtra utility types

VSXtra provides many utility types to carry out common tasks with in VS IDE. The implementation of the ClearRecentListBase class demonstrates a few of them:

public abstract class ClearRecentListBase : CommandHandlerBase

{

  protected override bool CanExecute(OleMenuCommand command)

  {

    return VsRegistry.GetFileEntryList(RecentListKey).Count > 0;

  }

 

  protected override void OnExecute(OleMenuCommand command)

  {

    var view = new ClearListView();

    VsRegistry.GetFileEntryList(RecentListKey).

      ForEach(item => view.Model.ListEntries.Add(item));

    if ((bool)view.ShowDialog())

    {

      VsIde.File.SaveAll();

      DeleteRecentFileList(view.Model.SelectedListEntries);

      VsIde.RestartVS();

    }

  }

  // --- Other members omitted

}

The VsRegistry static class provides functionality to access registry information related to the Visual Studio instance the current package runs in. It has properties like LocalRegistryRoot, GetFileEntriesList, etc. In the future this class will provide functionality to access many VS and package related information.

A second example is the VsIde static class that allows accessing many common properties and methods traditionally used through the DTE and DTE2 interfaces. VsIde is designed not just to wrap DTE2 functionality, but rather provide strongly typed methods and properties for common Visual Studio related tasks. I highlighted the RestartVS method that exactly does what its name says.

VsIde also provides a good starting point to execute VS commands. However, instead of using the DTE.ExecuteCommand(string, string) method, VsIde uses strong types providing compile-time checks. While we can mistype the ExecuteCommand with “File.SaveAl” and it will fail only at runtime, making the same mistake (omitting the last “l” from SaveAll would result a compile error. And even we can have IntelliSense support on typing command names...


Posted Aug 06 2008, 07:53 AM by inovak
Filed under:

Comments

Visual Studio Hacks wrote Visual Studio Links #62
on Thu, Aug 7 2008 15:37

My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. Whole Tomato Software and Fog Creek have teamed up on Source Links . Source links is a free Visual Studio extension that turns file

buy imitrex generic wrote re: LearnVSXNow! #29 - VSXtraCommands Part 2 — Commands removing recent items
on Sun, Feb 24 2013 22:20

RrPuws Very neat article post.Really thank you! Will read on...