Archive for the ‘Composite Application Block’ Category

Combined context menus in a CAB application

As with my previous post on context menus in CAB applications, this post may well only really apply to the following scenario.

The application is a composite style application using the Microsoft Composite Application Block (CAB) libraries. There are several independent couples that can be included/excluded without affecting the other modules. There is a common Domain Model that represents the pure business domain of the application; each module largely just acts as a UI/View for an aspect of the model. The Shell of the application makes use of the Infragistics ToolbarManager (Office 2007 ribbon style).

The next problem I encountered was that although a domain entity should have a common context menu for all modules, some additional options should only be available from some of the modules; for example one module supported multiple selection of the entity whereas another didn’t, therefore the ‘Filter on selected’ command only really made sense in one place.

After some thought I decided that the reason for the differences in the context menu options is that in each place there is a slightly different context; There is the context of the selected domain entity, along with the context of the control that was clicked on. Therefore I decided to split the context menu into different sections (each section would have its own heading label to indicate the context that the tools relate to), then when a right click is detected the module could make a call to the ContextMenuService to show a combined context menu, passing in the keys of all the context menu sections to show.

Previously with the ‘domain entity context menus’ the definition of the tools would live in the domain model; with the new local context menus the definition for the tools would reside in the module, clearly indicating that this context menu is not common, and relates chiefly to the module.

A problem I encountered with this approach is that the Infragistics toolbar manager does not have a built in method for showing multiple PopupMenuTools as a single context menu. Therefore my solution was that when a call was made to show a combined context menu a key would be created using the combination of all the context menus to be shown. A check would then be made to see if this specific combined context menu had already been created, if not, a new PopupMenuTool would be created, simply taking the tools from all the individual menus and adding them, in order, to the new menu.

This solution has worked remarkably well. There is an outstanding issue, in that if a tool is later added to one of the individual context menus it will not be picked up by any combined context menus already created; If this functionality was ever required it would be relatively simple to just catch when a tool was added to a context menu and make sure it was added to all the others at the same time; In my current application the context menus are defined at startup and never changed, so this problem never occurs.

Context menus in a CAB application

Recently I’ve been implementing right-click context menus in our application. The problems I encountered and the solution I reached may not be applicable to all CAB applications so I’ll give you the context (apologies for the bad joke!)

The application is a composite style application using the Microsoft Composite Application Block (CAB) libraries. There are several independent couples that can be included/excluded without affecting the other modules. There is a common Domain Model that represents the pure business domain of the application; each module largely just acts as a UI/View for an aspect of the model. The Shell of the application makes use of the Infragistics ToolbarManager (Office 2007 ribbon style).

The requirements I was trying to implement stated that if a representation of an entity in the domain model was right clicked on in any of the modules a context menu should be shown showing several commands that can be chosen for that entity. The commands in the context menu may act on one or more modules.

Problem 1 – Where should the code live?

The first problem I encountered was where should the context menus be created? If created in one/all of the modules then how do we maintain inter-module independence? We could end up with the same context menu duplicated in several of the modules. We could end up with a context menu that contains commands that act on a module that hasn’t been included. We could end up with modules communicating with each other (through some sort of interface to register commands with each other’s context menus – like UIExtensionSites in CAB).

So if not in a module then perhaps in the shell? This has the problem that the shell is generic and not tied to the domain (we even use the same shell in another application); it would be undesirable for the shell to be dependent upon domain model concepts.

This leaves the domain model as a possibiltiy, however, as we don’t want UI concerns in the domain model (like context menus). We need to create a part of the domain model that is about UI, it will act pretty much like it’s own module but will be a dependency for all/many of the modules (I believe the Smart Client Software Factory calls these Foundation Modules).

Problem 2 – What are the responsibility boundaries and the interfaces?

I decided that as much of the definition of the context menu should be in a ContextMenuService in the new domain.UI project. This class would define all the tools on the menu and interact with the shell to add them (The ToolbarManager needs the tools to be registered as root tools in the shell). Any tool that acted on a module (or many modules), would start off invisible; When the module is loaded it will communicate with the ContextMenuService and specify the tool keys that it will respond to, the first module to specify a tool will make the tool visible in the context menu (subsequent modules will have no effect).

Each module will handle the right-click event and tell the ContextMenuService to show the context menu for the clicked on instance of the domain entity. (This will also ’set the context’ for the menu modifying menu options based on the instance). Finally the ContextMenuService will call through to the Shell to instruct it to show the context menu at the current mouse location.

Upgrading CAB solution to Visual Studio 2008 and making all the tests pass

For one reason or another we’ve recently upgraded the Microsoft Composite Application Block solution to a Visual Studioo 2008 solution. The conversion appeared to succeed, but when we tried to run the unit tests we had lots of failures. I then went through trying to figure out whether these failures represented functional failings in the CAB built from this source (this would be a ‘bad thing’) Or whether they were issues with the tests.

This post details the steps required to fix all the unit tests

Expected Exception Attribute not working

The first problem seemed to be that any test that had an ExpectedException attribute failed, with the reason being that an exception was thrown… hang on… isn’t this what we wanted? Seems that the attribute wasn’t being recognised by the unit test framework (MSTest). The cause being that the test projects had a reference to the wrong version of the MSTest dll. So although Visual Studio was using MSTest 2008 to run the tests it was looking for attribute definitions in another version of the dll… Seems like this should have been picked up by the conversion wizard. Anyhow, it’s a simple fix, remove all the references to Microsoft.VisualStudio.QualityTools.UnitTestFramework and add them again making sure you get the V9.0 dlls.

AppDomain Base Directory has changed

The next issue I resolved was a little more tricky. Several tests were failing in the FileStatePersistenceService, and after some digging it looked like it was because there were lots of relative addresses being used for generating files, the files were therefore being created in the AppDomain.CurrentDomain.BaseDirectory, but then being looked for in the Environment.CurrentDirectory. In MSTest 2005 these happened to be the same location. Due to a change in MSTest 2008 they are no longer the same. This page explained the problem and a fix, which simply involves adding a line to run before the test that changes the BaseDirectory.

AppDomain.CurrentDomain.SetData(“APPBASE”, Environment.CurrentDirectory);

Namespace changes on embedded resources

The next issue was one found in ReflectionModuleEnumeratorFixture and ModuleLoaderServiceFixture. Both of these test fixtures involved dynamically compiling classes from embedded resources. (I can’t help but wonder if this is overkill for a unit test). Anyway, this was kind of hard to diagnose, the only problem being that a stream was being created from the ExecutingAssembly().GetManifestResourceStream(input), and this was returning null. After debugging and looking at what was returned from GetManifestResourceNames() I noticed that there was a mismatch in the names being looked for and those used for the embedded resources. To fix the tests I changed all the calls to compile files in the constructor to reference the correct names. This involved replacing Microsoft.Practices.CompositeUI.Tests.Mocks.Src with Microsoft.Practices.CompositeUI.Tests.Instrumentation.Mocks.Src

Last Test – LoadModuleReferencingMissingAssembly

The final test to outsmart me was the LoadModuleReferencingMissingAssembly test, this test attempts to load a module that calls out to another module that has not been included  in the ModuleInfo. An exception should be thrown when the call is made to Module.load(). However in 2008 no such exception is thrown, with execution proceeding as normal. In 2005 a FileNotFound exception is thrown saying that it can’t find the referencedAssembly. In both cases the dll is present in the output directory. At the time of writing I have been unable to fix this test, I wonder if the issue is related to the AppDomain changes, but the proposed fix doesn’t seem to work.

Any suggestions more than welcome!