July
10

Several months have passed since people starting using C# 3.0 out there. I, however, was busy with linear algebra, discrete math and such at that time.

I did, however, try to keep up and see what’s the fuss about extension methods, but I never got it. I mean, this is anti-encapsulation at it best - break into any type, do whatever you feel like. Total chaos.

So I gave it some time. I didn’t force it into any of my projects until the time was right. Then I finally got it - extension methods are ideal for little pieces of code which you need, but creating a utility class for them feels wrong.

For example, I was implementing a new feature for Regionerate a couple of days ago in which I had to sort a list, split it into distinct values and recursively sort it again.

Its a reflection-based sort and it has quite a bit of logic in it, so it had a class & unit tests just for it. I had to take care of the splitting thingy, but it felt wrong to add it as a method in the sort class, as it operates on lists. It really feels like a method that should run on IList<T>.

Subclassing List<T> for the job feels wrong - c’mon, how would you pitch such a class? “It’s a list that you can split!”. Unpersuasive.

That’s how I got it: If IList<T> was built especially for Regionerate, it would have had a reflection-based Split function, but since its not, I should implement it as an extension method.

Took me 2 minutes and works like a charm.

   1:  public static IDictionary<object, IList<T>> Slice<T>(
   2:          this IList<T> list, PropertyInfo propertyInfo)
   3:  {
   4:      IDictionary<object, IList<T>> slices = 
   5:          new Dictionary<object, IList<T>>();
   6:      foreach (T t in list)
   7:      {
   8:          // Get the value of propertyInfo.
   9:          object value = propertyInfo.GetValue(t, null);
  10:   
  11:          // Add it to slices.
  12:          if (slices.Keys.Contains(value))
  13:          {
  14:              // slices already has a slice for this value.
  15:              slices[value].Add(t);
  16:          }
  17:          else
  18:          {
  19:              // there is no slice for this value 
  20:              // inside slices, create a new slice.
  21:              IList<T> newSlice = new List<T>();
  22:              newSlice.Add(t);
  23:              slices.Add(value, newSlice);
  24:          }
  25:      }
  26:   
  27:      return slices;
  28:  }

A fully documented, well-aligned version of this extension method is freely available here.

kick it on DotNetKicks.com

0
August
9

After yesterday’s adventure of adding buttons to Visual Studio’s Solution Explorer, I just had to post a short follow-up that shows how easily the same task can be done in #develop’s Projects pad. To remind you, what I wanted to do was add two buttons - one for the project context menu and one for the solution context menu.

While the Solution Explorer adventure required some coding, the Projects pad one is almost nothing but XML.

Simply open up your .addin file and add two Path elements under your AddIn element.

   1:  <AddIn name        = “My Add-in”
   2:         author      = “Omer Rauchwerger (rauchy)”
   3:         url         = “http://blog.rauchy.net”
   4:         description = “Does stuff.”>
   5:   
   6:  
   7:    
   8:      <Path name=”/SharpDevelop/Pads/ProjectBrowser/ContextMenu/ProjectNode”>
   9:              <MenuItem id = “DoStuffOnProject”
  10:                    label = “Do stuff on this project”
  11:                    class = “MyNamespace.ProjectCommand”/>
  12:      </Path>
  13:      <Path name=”/SharpDevelop/Pads/ProjectBrowser/ContextMenu/SolutionNode”>
  14:              <MenuItem id = “DoStuffOnSolution”
  15:                    label = “Do stuff on this solution”
  16:                    class = “MyNamespace.SolutionCommand”/>
  17:      </Path>
  18:  </AddIn>

The first Path element creates a button labeled “Do stuff on this project” and places it on the context menu that pops up when your right-click a project in the Projects pad. It also hooks it up with the “MyNamespace.ProjectCommand” class. The second Path element does the same but for solutions, and hooks it up with the “MyNameSpace.SolutionCommand” class.

ProjectCommand and SolutionCommand are two classes you should create which inherit from AbstractMenuCommand. All you need to implement in these classes is the Run method. The Run method will run whenever someone clicks on the button.

   1:  using ICSharpCode.Core;
   2:   
   3:  namespace MyNamespace
   4:  {    
   5:      public class SolutionCommand : AbstractMenuCommand
   6:      {
   7:          public override void Run()
   8:          {
   9:              // TODO: Handle the Click event.
  10:          }
  11:      }
  12:  }

Gosh I love #develop extensibility :-)

kick it on DotNetKicks.com

0
August
8

I’d like to share today’s experience of adding buttons to the solution and project context menus in Visual Studio 2005’s Solution Explorer window. (I ended up with this)
Seems like everything related to Visual Studio extensibility is overly complicated, but unlike other extensibility tasks, this one is rather simple.

Step 1 will be to find our CommandBar.

The CommandBar is our target where we would like to place our buttons. In my case, I wanted to add a button to the context menu that pops up when you right-click on a solution or project. You can retrieve your CommandBar object from the applicationObject.CommandBars collection by specifying its name.

   1:  CommandBars commandBars = ( CommandBars )applicationObject.CommandBars;
   2:  CommandBar commandBar = commandBars[ “Solution” ];

Solution” represents the context menu that pops up when you right-click solutions in the Solution Explorer and “Project” represents the one for projects.

In step 2 we will create the actual button.

The type of this button control is CommandBarButton. In spite of what you might think, you can’t just initialize it by using new CommandBarButton(), you have to get your instance by calling the Add method on your CommandBar.
Here is how the CommandBar.Add method looks like: (don’t copy & paste this code)

CommandBarControl Add(object Type, object Id, object Parameter, object Before, object Temporary);

Don’t ask me why everything is object based, I’m guessing it has something to do with the fact that the entire model is COM based. oh well.
The CommandBarButton is created this way:

   1:  CommandBarButton button = ( CommandBarButton )commandBar.Controls.Add( MsoControlType.msoControlButton, Missing.Value, Missing.Value, 1, true );
   2:  button.Caption = “My Button”;
 

You can compile your solution and run it, you will be able to see your button in the Solution Explorer.
This is all good, but a button that doesn’t do anything is really not that handy nowadays so we’ll have to subscribe to its click event.

Step 3: Doing stuff when the button is clicked.

Well, you guessed it, we can’t do that simply by registering to the button’s OnClick event, cause there isn’t one. We have to register through the button’s CommandBarEvents object.
The CommandBarEvents class exposes the Click event for your button. Here’s how to add some event handling code for the Click event:

   1:  CommandBarEvents myButtonEvents = ( CommandBarEvents )applicationObject.Events.get_CommandBarEvents( myButton );
   2:  myButtonEvents.Click += 
   3:        delegate( object CommandBarControl, ref bool Handled, ref bool CancelDefault )
   4:            {
   5:                // TODO: Handle the Click event.
   6:                Handled = true;
   7:            };

And now for a tricky part: since you get your instance of CommandBarEvents inside the scope of a method, when the method ends, the Garbage Collector collects it, leaving all the event handlers orphaned. Unless you keep your instance safe from the jaws of the mighty Garbage Collector, your buttons will not respond to clicks.
To do so, just keep your CommandBarEvents instance(s) as member fields of your class. Once your class is disposed, they will be disposed as well.

kick it on DotNetKicks.com

1