I received a question the other day on building menu's in a win forms application. I wasn't sure of a clean way of doing it, so I thought I would put together a sample app to see if I could come up with something. I'm not sure I'm completely happy with what I've got so far, but my goal was to be able to drop in new menu items, and menu groups without a lot of ceremony and configuration.

The guts of it depends on castle windsor to glue most of the pieces together using the mass component registration api. I found it really hard to test, but was please with how easy it just kind of worked!

 1 public class WindsorContainerFactory : IWindsorContainerFactory {
 2       private static IWindsorContainer container;
 3       private IComponentExclusionSpecification criteriaToSatisfy;
 5       public WindsorContainerFactory() : this(new ComponentExclusionSpecification()) {}
 7       public WindsorContainerFactory(IComponentExclusionSpecification criteriaToSatisfy) {
 8           this.criteriaToSatisfy = criteriaToSatisfy;
 9       }
11       public IWindsorContainer Create() {
12           if (null == container) {
13               container = new WindsorContainer();
14               container.Register(
15                   AllTypes
16                       .Pick()
17                       .FromAssembly(GetType().Assembly)
18                       .WithService
19                       .FirstInterface()
20                       .Unless(criteriaToSatisfy.IsSatisfiedBy)
21                       .Configure(
22                       delegate(ComponentRegistration registration) {
23                           this.LogInformational("{1}-{0}", registration.Implementation, registration.ServiceType.Name);
24                           if (registration.Implementation.GetInterfaces().Length == 0) {
25                               registration.For(registration.Implementation);
26                           }
27                       })
28                   );
29           }
30           return container;
31       }
32   }

The other neat piece that kind of made things easy to get up and running was the concept of a default repository. (I picked up this bit of knowledge from Oren at DevTeach.)

 1 public class DefaultRepository<T> : IRepository<T> {
 2       private IDependencyRegistry registry;
 4       public DefaultRepository(IDependencyRegistry registry) {
 5           this.registry = registry;
 6       }
 8       public IEnumerable<T> All() {
 9           return registry.AllImplementationsOf<T>();
10       }
11   }

This was the only implementation of a repository in the system, and it was used for a IRepository and IRepository. I just created a new implementation of an IMenuItem or ISubMenu and it picked it up via Windsor's mass component registration.

 1 public class MainMenuPresenter : IMainMenuPresenter {
 2       private readonly IMainMenuView mainMenu;
 3       private readonly IRepository<ISubMenu> repository;
 4       private readonly ISubMenuItemComparer comparer;
 6       public MainMenuPresenter(IMainMenuView mainMenu, IRepository<ISubMenu> repository, ISubMenuItemComparer comparer) {
 7           this.mainMenu = mainMenu;
 8           this.repository = repository;
 9           this.comparer = comparer;
10       }
12       public void Initialize() {
13           foreach (var subMenuToAddToMainMenu in repository.All().SortedUsing(comparer)) {
14               mainMenu.Add(subMenuToAddToMainMenu);
15           }
16       }
17   }

I also spent a little time playing with Gallio. I had some issue with conflicts between the version of Castle.Microkernel that I was toying with and the one that comes with gallio. I wasn't able to resolve the issue, but after looking into the concept behind Gallio, I like the idea. Kind of neat stuff!

Here's what I came up... Thank you Mr. JP for the inspiration!

Source can be downloaded here!

I can't stress how many ideas in this project came from concepts learned from the Nothin' But .NET boot camp. If you're in the area, you should definitely go check out the Vancouver course coming up next month!

comments powered by Disqus