Thursday, June 28, 2012

A Pluggable Framework for the Asterisk Test Suite - Part 1

Asterisk Test Suite - a (very) brief Overview

On the Asterisk development team, we attempt to write software using an Agile methodology (specifically, the "Scrum" flavor).  As part of this development process, we perform continuous integration using Atlassian Bamboo, which, in addition to doing a basic build check, also executes sets of tests against the current build. There's a myriad of reasons to do continuous integration - they're almost too many to list - but the most obvious of these is that we get a consistent sanity check as to the state of the code at all times.

The tests that the Bamboo server runs come in two forms: unit tests, as part of the Asterisk Unit Test framework, and functional tests, as part of the Asterisk Test Suite.  The Asterisk Test Suite is a freely available external tool that orchestrates these tests against one or more instances of Asterisk.  These tests cover a large range of functionality - everything from SIP compliance, to channel technology interoperability, to ensuring that Asterisk applications and functions work as intended.

Each test is essentially a stand-alone entity - the Asterisk Test Suite does not mandate what language a test is written.  Organically, the Test Suite has moved towards Python, but it still includes tests written in a host of other languages (most notably Lua, but there's also some bash ones in there that no one enjoys maintaining).  As the tests have grown, we've added to the libraries that the Asterisk Test Suite provides to try and minimize reproduction of functionality and to minimize the amount of time that it takes to write a test.

While the Test Suite is very flexible - it will run any executable file named 'run-test' - that flexibility has cost us in having a lot of repeated, boilerplate code.  In the current state of the Test Suite, the Python tests typically inherit from a common base class, TestCase, that does a lot of the heavy lifting of starting/stopping Asterisk, creating an AMI connection, and exposing the basic AMI events that allow the test logic to be inserted. Even still, the tests can get a bit repetitive.

Two Current Tests: cdr_accountcode and cdr_userfield

The following two tests - cdr_accountcode and cdr_userfield (which tests that the AccountCode and UserField values are recorded properly in CDR records) - illustrate the general problem.  The tests inherit from CDRTestCase, which in turn inherits from TestCase.  Besides the complexity of having multiple levels of inheritance, there is still some repeated elements to the meat of these two tests.

cdr_accountcode:

#!/usr/bin/env python
'''
Copyright (C) 2012, Digium, Inc.
Walter Doekes

This program is free software, distributed under the terms of
the GNU General Public License Version 2.
'''

import sys
sys.path.append("lib/python")
from asterisk.CDRTestCase import CDRTestCase
from asterisk.asterisk import Asterisk
from asterisk.cdr import AsteriskCSVCDR, AsteriskCSVCDRLine
from twisted.internet import reactor
import re

class CDRAccountCodeTest(CDRTestCase):
    def __init__(self):
        CDRTestCase.__init__(self)

        # 3@default -> (answer)
        # accountcode: third
        self.add_expectation("Master", AsteriskCSVCDRLine(source="",
            accountcode="third",
            destination="3", dcontext="default", callerid="",
            channel="Local/3@default-.*", dchannel="",
            lastapp="Hangup", lastarg="",
            disposition="ANSWERED", amaflags="DOCUMENTATION",
        ))
        # NOTE: I removed some of the additional expectations
        # for brevity

def main():
    test = CDRAccountCodeTest()
    test.start_asterisk()
    reactor.run()
    test.stop_asterisk()
    return test.results()

if __name__ == '__main__':
    sys.exit(main())

# vim: set ts=8 sw=4 sts=4 et ai:


cdr_userfield:

#!/usr/bin/env python
'''
Copyright (C) 2010, Digium, Inc.
Terry Wilson

This program is free software, distributed under the terms of
the GNU General Public License Version 2.
'''

import sys
sys.path.append("lib/python")
from asterisk.CDRTestCase import CDRTestCase
from asterisk.asterisk import Asterisk
from asterisk.cdr import AsteriskCSVCDR, AsteriskCSVCDRLine
from twisted.internet import reactor
import re

class CDRUserFieldTest(CDRTestCase):
    def __init__(self):
        CDRTestCase.__init__(self)

        self.add_expectation('cdrtest_local',AsteriskCSVCDRLine(source="", 
            destination="1", dcontext="default", callerid="",
            channel="Local/1@default-.*", dchannel="", lastapp="Hangup", lastarg="",
            disposition="ANSWERED", amaflags="DOCUMENTATION", userfield="bazinga"
        ))


def main():
    test = CDRUserFieldTest()
    test.start_asterisk()
    reactor.run()
    test.stop_asterisk()
    return test.results()

if __name__ == '__main__':
    sys.exit(main())


Some obvious things in this comparison:
  • The act of setting up the test case class, starting Asterisk, running the twisted reactor, stopping Asterisk, and returning a result is all functionality that a single entry point could do, if it knew what object to instantiate
  • The object being instantiated is identical, save for what CDR information it expects to match on
  • The CDR information that a match must be made on can be configuration driven
Since common classes and modules can provide the functionality these tests use, and the differences between the tests can be driven by configuration, why not ... do that?


A Pluggable Framework

Since tests already define their configuration in a YAML file, the idea is to use that configuration data to drive  all of the test's behavior.  This includes what modules are instantiated to support test execution, what data is needed to configure them, and what the expected results of the test should be.

Since all tests are spawned as a separate process, a new module - TestRunner (what a creative name...) - is responsible for having an entry point and building the test objects specified in the configuration.  TestRunner parses the test's YAML file, looking for modules to locate and instantiate.  In the next post I'll go more into how that happens - there's one aspect of this that I think is pretty cool and gets around some of the requirements Python has for defining packages.

Loadable modules currently fall into one of two categories: Test Objects, and Pluggable Modules.  A Test Object is responsible for starting and stopping Asterisk and orchestrating the test activities.  Pluggable Modules add bits of functionality into the test - things like verifying CDRs/CELs, adding AMI event listening and verification, etc.  These categories may have to expand in the future - and the role of a Test Object defined more narrowly - but it works well for our purposes now.

As an example, say we have a test-configuration that defines a Test Object SimpleTestCase (in module SimpleTestCase (and yes, per PEP8, this should be lower case - Pythonic compliance has not traditionally been our strongest suit, but we're working on that)):

test-modules:
    test-object:
        config-section: test-object-config
        typename: 'SimpleTestCase.SimpleTestCase'

test-object-config:
    spawn-after-hangup: True
    test-iterations:
        -
            channel: 'Local/1@default'
            application: 'Echo'



The TestRunner parses the test-modules configuration section and determine that it needs to create a Test Object.  The YAML file itself defines the Keyword (test-object-config) that contains the configuration information for this object.  TestRunner takes the generated in memory representation of the YAML and passes that in to the constructor of the TestObject.

    # NOTE: Some code removed here for brevity
    test_object_spec = test_config['test-modules']['test-object']

    module_obj = load_and_parse_module(test_object_spec['typename'])
    if module_obj is None:
        return None

    test_object_config = None
    if ('config-section' in test_object_spec and
        test_object_spec['config-section'] in test_config):
        test_object_config = test_config[test_object_spec['config-section']]
    else:
        test_object_config = test_config

    # The test object must support injection of its location as a parameter
    # to the constructor, and its test-configuration object (or the full test
    # config object, if none is specified)
    test_obj = module_obj(test_path, test_object_config)


Note that a test object gets two things: its relative location to the current process directory (so it can find its test specific files), and the in-memory YAML object configuring it.  The method load_and_parse_module does the work of separating the typename into package/module/classname parts and importing the module.


def load_and_parse_module(type_name):
    ''' Take a qualified module/object name, load the module, and return
    the type specifying the object

    Parameters:
    type_name A fully qualified module/object to load into memory

    Returns:
    An object type to be instantiated
    None on error
    '''


    LOGGER.debug("Importing %s" % type_name)

    # Split the object typename into its constituent parts - the module name
    # and the actual type of the object in that module
    parts = type_name.split('.')
    module_name = ".".join(parts[:-1])

    if not len(module_name):
        LOGGER.error("No module specified: %s" % module_name)
        return None

    module = __import__(module_name)
    for comp in parts[1:]:
        module = getattr(module, comp)
    return module



And voila: we have an in-memory object that acts as our test!

TestRunner does the mechanics of starting the twisted reactor and telling the Test Object to run - which takes the part of the entry point mechanics that was reproduced across all tests.  So, now that we can create a Test Object and tell it to do stuff, we need to figure out how to actually verify the purpose of those tests: CDR records.

In the next post I'll go into more detail about the Pluggable Modules - specifically the CDR Module - and how they interact with the Test Object.  We can then put the pieces together to see how the CDR tests above are configured to obviate the need for the run-test scripts.

Thursday, June 21, 2012

So... yeah. Changes.

Its been awhile since I've written anything here.  The original plan - back when I was writing the posts on WPF - was to document aspects of a project I was working on that used Prism, Unity, and WPF.  It wasn't a very complex project, but it was a lot of fun - at least the Prism portion.

As it turns out, that project died a quiet death, and I got bored documenting something that I no longer had a reason to be tinkering with.  After that... I stopped writing here.

And then a bunch of stuff happened.  Without going into a ton of detail, I discovered that I was the only person generating revenue for the company that I worked for.  When your business is Engineering Contract Services, that's not a good sign.  So I started looking.

And I ended up at a fantastic company - Digium - working on the open source project Asterisk.

You know how you sometimes think of the way things should be in software development?  The people you'd like to work with, the things you'd like to be working on, the environment you'd like to be in?  I found myself there.  Its pretty fantastic.

I did go from working primarily in Microsoft venues - often in the .NET ecosystem (although the last contract I was on was C++ on a RedHawk Linux OS) - to working on Linux systems in C.  But its been an absolute blast.

(And to scratch that OO itch, there's always the Asterisk Test Suite for some Python goodness.)

So, a few small goals of mine:

  1. Write something now and again.  I'm shooting for 1 post a week.  That may be a bit ambitious however, but we'll see.
  2. Write about Asterisk development.  There's some great stuff coming down the pipeline in Asterisk 11.
  3. Learn Italian.

Monday, December 27, 2010

Creating Dynamic Menus in WPF and Prism - Part 4

So, last time I noted that my approach was less than, uhm, optimal.  In fact, it was pretty bad.  At least it didn't involve convoluted code behind!  Anyway.

So, I'd like to have a nice, dynamic menu or toolbar (yup, either or both) that Prism modules can add items to.  It'd be nice if they could place those items where they need them, such that the menus are still ordered in a useful manner for the user.  It'd also be nice if a module could add an item that was always displayed, versus an item that is only displayed when a view in the module is active. 

Whew.

Spec the code.  Design the code.  Implement the code.  (Okay, so I didn't do that completely, and I paid for it.  But let's pretend that I practice what I preach...)

  1. The menu / toolbar service should not be tied to its view.  That is, items added should be able to be displayed in a menu, toolbar, "ribbon", or some hybrid thereof.
  2. Modules should be able to differentiate between the various types however - I should know if I'm adding an item to a menu or a toolbar.
  3. Modules should be able to specify whether an item has a parent (which can be any previously added item), and place the item relative to some other child of that parent.
  4. Modules should be able to add a seperator.
  5. Items that are added can be either permanent (always shown), or tied to the activity of the module.
Design decisions time!

You'll note that I already defined that the dynamic menu / toolbar thingy should be a service - based on the shellacking of my previous attempt, its become pretty obvious that this thing should be a service interface in the Prism project's Infrastructure DLL.  I didn't list that in the requirements, but it probably should be.

The first requirement should be pretty easy to meet - the service can expose an ObservableCollection of items, and the various UI elements can use a HierarchicalDataTemplate to format the collection.  This does mean that I'll probably need multiple implementations of the service however (requirement #2) - that shouldn't be a problem however using Unity's Resolve(string name) overload.

Requirement three means that each item will have to have children items, and the service should:
  • expose a way to add an item that optionally includes a parent and a predecessor
  • expose an IEnumerable<> of items, so that modules can query for parents / predecessors
  • (maybe?) expose a way to query for items, since the hierarchical nature of the data means queries will have to be recursive (and writing recursive LINQ operators everywhere would kinda suck)
Requirement four: items can be just a separator.  Boolean field for the win!

Requirement five is tricky.  There's a couple of ways Prism handles what is viewed / active:
  1. IActiveAware.  Views can implement this interface, which gives you a boolean field indicating whether or not the view is active, and an event that can be subscribed to when that field changes.  This is tied to a Region's concept of what is active.  If we allow modules to provide an IActiveAware object, a menu item could be tied to that, and we could show / hide a menu item based on that object.
  2. The service could implement INavigationAware.  This would give us notification when a navigation request is made to some object.  I'm not sure what happens if we register an object that is INavigationAware that is not designed to handle a navigation URI request - in essence, we want our service to snoop navigation, not actually perform in it.
  3. A PresentationEvent, that modules can fire when they want their items shown or hidden.
Option #1 provides a lot of granularity, as each View can have menu items added / removed.  On the other hand, it may provide too much granularity, and we may find ourselves adding / removing items when we don't want to.  We'd have to be careful as to what object implementing IActiveAware is sent to the service.

Option #2 feels a little fishy.  While it seems ideal, I don't like our service being a navigation object when it isn't; that, and at least two of the methods (OnNavigatedTo and OnNavigatedFrom) would never be called.  Implmenting half of interfaces always feels a little bad, so I'm inclined not to pick that route.

Option #3 gives the most granularity, but also requires more out of the users of the service.  I want this to be as "fire and forget" as possible - I put in my menu items, and I move on.

So, I'm probably going to go with Option #1.

Lots of design decisions made, with a lot of tradeoffs.  Next time: more design decisions, and some initial implementation.

Saturday, December 25, 2010

Creating Dynamic Menus in WPF and Prism - Part 3

This may be the topic that won't die.  After the train wreck that was my first attempt at creating a dynamic menu in WPF / Prism (see the past two blog posts, plus my question on StackOverflow), I ended up getting a pretty nice dynamic menu working using what Robert Rossney suggested (again, see that post on StackOverflow...).  My approach generally followed the following:
  1. The menu (or pseudo-toolbar) was implemented in its own Prism Module.  Other modules obtained the service by referencing the module, and could add menu items by accessing the service.
  2. Menu items were added by specifying a command, menu name, a reference to an image to display, and optionally, a parent menu item.
The meat of this approach is below.  A ViewModel contains an ObservableCollection of ToolbarItems, while a View interprets those items as a menu.  The toolbar service exposes a method AddMenu that modules can call to add their items:


///
/// Add a menu item to the toolbar
///

public void AddMenu(Action<object>callbackFunction, string menuName, string iconLocation, string parentMenu)
{
   if (String.IsNullOrEmpty(menuName))
      throw new ArgumentNullException("menuName");
   if (ExistingMenuNames.Contains<String>(menuName))
      throw new InvalidOperationException("Cannot add a menu item with the same name as an existing menu item");

   ToolbarObject newObject = new ToolbarObject(
      menuName,
      iconLocation,
      new CompositeCommand());

   // Add a command, if available
   if (callbackFunction != null)
      newObject.Command.RegisterCommand(new DelegateCommand<Object>(callbackFunction));

   // Set up the parent menu, if available
   if (!String.IsNullOrEmpty(parentMenu))
   {
      if (!ExistingMenuNames.Contains<String>(parentMenu))
         throw new InvalidOperationException("Cannot add a menu to a parent menu item that doesn't exist");
      if (_model == null)
         _model = _container.Resolve<IToolBarPresentationModel>();

      var parent = (from item in _model.ToolbarItems
            where String.Equals(item.Name, parentMenu, StringComparison.InvariantCulture)
            select item).Single<ToolbarObject>();
      parent.Children.Add(newObject);
   }
   else
   {
      // Insert after Main, keeping Help last
      _model.ToolbarItems.Insert(1, newObject);
   }
}


The big issue I had run into before was actually displaying the items in the View appropriately. Enter the wonderful HierarchicalDataTemplate, and its little (very necessary) cousin, ItemContainerStyle. The view code using these two is below.


   <UserControl.Resources>
      <model:ToolBarPresentationModel x:Key="modelData" />
      <Style TargetType="MenuItem">
         <Setter Property="Command" Value="{Binding Path=Command}"/>
         <Setter Property="Foreground" Value="White"/>
      </Style>
      <HierarchicalDataTemplate DataType="{x:Type model:ToolbarObject}"
                         ItemsSource="{Binding Path=Children}">
         <HierarchicalDataTemplate.ItemContainerStyle>
            <Style TargetType="MenuItem">
               <Setter Property="Command" Value="{Binding Path=Command}"/>
            </Style>
         </HierarchicalDataTemplate.ItemContainerStyle>
         <StackPanel VerticalAlignment="Top" Margin="5,0,5,0">
            <Image Height="24" VerticalAlignment="Center" Source="{Binding Path=ImageLocation}"/>
            <ContentPresenter Content="{Binding Path=Name}" HorizontalAlignment="Center"/>
         </StackPanel>
      </HierarchicalDataTemplate>
   </UserControl.Resources>
   <UserControl.DataContext>
      <Binding Source="{StaticResource modelData}"/>
   </UserControl.DataContext>
   <Grid>
      <Menu Height="48" Margin="5,0,5,0" Name="MainMenu" VerticalAlignment="Top" Background="Transparent"
         ItemsSource="{Binding}">
      </Menu>
   </Grid>


This code creates a menu where each menu item in the parent menu can have children, or be a clickable menu item itself.  Each menu item provides its own path to a resource, such that each menu item shows an image and a text description.  Due to the limited nature of the application, the first menu is always kept as Main (or File), while the last is always kept as Help.

While this approach worked great for the application at hand, its not very useful for a general application.  To whit, the following are some of the obvious drawbacks:

  1. First come, first served.  If Module A adds an item to the menu without a parent, that will get placed after Main.  If Module B does the same, then it will get added after Main, pushing Module A's menu further down the line.  This may not be desireable.
  2. Nesting of menus only goes down one level.  If you specify a parent that is not in the first row of the menu, the parent won't be found.
  3. Specifying an Action as the parameter only gives us a callback, and doesn't allow multiple modules to tie a callback to a single menu option.  This works fine if a menu option should only be handled by a single module, but works poorly if a number of modules need to respond to a menu click, e.g., Save or Exit.
  4. Menu options that are added under a parent are added on a first come, first served basis.  This can lead to some odd and confusing orderings, depending on the Module loading.
  5. No separators.  Ugh.
  6. The toolbar service module should not have to be referenced directly by other modules.
  7. Does everything really need an image?  This approach was supposed to emulate (to a very, very limited extent) a Ribbon-style control, combining both menu / toolbar approaches.  While kind of fun and quirky, its not appropriate for a typical line of business application.
Okay, so this approach kind of, well, sucks.  But we learn from our mistakes.  Next time: doing it better, part 1!  (Or is it Part 4?)

Edit

Also: Merry Christmas!  The fact that I'm interested in writing about code again may be an "end of the year" thing, but I'll see where it takes me for now.

Saturday, September 18, 2010

WPF, Prism, and Creating Dynamic Menus - Part 2

Continuing my post from last time...

So my question on StackOverflow ended up getting a great answer that worked perfectly.  Where did I go wrong?

I listened to advice on teh internets (and I'm still learning WPF, which, if I knew it better, would have precluded me from going down this wonky path at all).  The "path" I ended up going down had a dynamic menu being created in a HierarchicalDataTemplate (good), but the actual content of the menu being generated in a load event in the code-behind (bad).

It's not that I'm against code in the code-behind.  I think there are times where it does make sense - take click event handlers in a ListView, for example.  There isn't a great way to route that through an ICommand object, at least that I'm aware of.  Often you aren't going to really do anything in the click handler - you just need to pass it back to the PresentationModel / ViewModel, which has all the logic to do the action of the click anyway.  You just need to handle the click.  And, unlike a menu, toolbar, or other button, you probably have a one-to-one relationship between the click handler and the method in PM/VM that will handle the action (so the benefit of an ICommand object is lessened somewhat).  Anyway.

That rant over, I pretty much knew I was hosing myself when I had written this blob of code:





private void ContentPresenter_Loaded(object sender, System.Windows.RoutedEventArgs e)
{

   ContentPresenter presenter = sender as ContentPresenter;

   if (sender != null)
   {
      DependencyObject parentObject = VisualTreeHelper.GetParent(presenter);
      bool bContinue = true;

      while (bContinue
         || parentObject == null)
      {
         if (parentObject is MenuItem)
            bContinue = false;
         else
            parentObject = VisualTreeHelper.GetParent(parentObject);
      }
      var menuItem = parentObject as MenuItem;

      if (menuItem != null)
      {

         ToolbarObject toolbarObject = menuItem.DataContext as ToolbarObject;
         StackPanel panel = new StackPanel();
         if (!String.IsNullOrEmpty(toolbarObject.ImageLocation))
         {
            Image image = new Image();
            image.Height = 24;
            image.VerticalAlignment = System.Windows.VerticalAlignment.Center;

            Binding sourceBinding = new Binding("ImageLocation");
            sourceBinding.Mode = BindingMode.TwoWay;
            sourceBinding.Source = toolbarObject;

            image.SetBinding(Image.SourceProperty, sourceBinding);

            panel.Children.Add(image);

         }

         ContentPresenter contentPresenter = new ContentPresenter();
         Binding contentBinding = new Binding("Name");
         contentBinding.Mode = BindingMode.TwoWay;
         contentBinding.Source = toolbarObject;
         contentPresenter.SetBinding(ContentPresenter.ContentProperty,
            contentBinding);
        
         panel.Children.Add(contentPresenter);

         menuItem.Header = panel;

         Binding commandBinding = new Binding("Command");
         commandBinding.Mode = BindingMode.TwoWay;
         commandBinding.Source = toolbarObject;
         menuItem.SetBinding(MenuItem.CommandProperty, commandBinding);
      }
   }
}


Yeah, that's no good at all. The end result of this was a "blank" menu, where the non-rendered items were clickable, but no rendering was done on the StackPanel embedded in the MenuItem's Header. Close, but no cigar.

Luckily, you can handle this pretty easily using the ItemContainerStyle property of a HierarchicalDataTemplate.  (I added the additional Style directive to handle the case where the command needs to occur on an item in the first row of the Menu)



<UserControl.Resources>

   <model:RecapToolBarPresentationModel x:Key="modelData" />
   <Style TargetType="MenuItem">
      <Setter Property="Command" Value="{Binding Path=Command}"/>
   </Style>
   <HierarchicalDataTemplate DataType="{x:Type model:ToolbarObject}"
      ItemsSource="{Binding Path=Children}">
      <HierarchicalDataTemplate.ItemContainerStyle>
         <Style TargetType="MenuItem">
            <Setter Property="Command" Value="{Binding Path=Command}"/>
         </Style>
      </HierarchicalDataTemplate.ItemContainerStyle>
      <StackPanel VerticalAlignment="Top" Margin="5,0,5,0">
         <Image Height="24" VerticalAlignment="Center" Source="{Binding Path=ImageLocation}"/>
         <ContentPresenter Content="{Binding Path=Name}" HorizontalAlignment="Center"/>
      </StackPanel>
   </HierarchicalDataTemplate>
</UserControl.Resources>



Lessons Learned:
  1. I've got a lot to learn in WPF still.  Knowing enough to get some basic ListViews displayed (and enough to get Prism more or less working for me) is great and all, but the more complex DataTemplating is still a learning ground.  Good stuff though - the power of WPF when compared against WinForms (or worse, MFC) is simply astounding.
  2. Watch out for advice coming teh internets.  StackOverflow's ratings really do provide a nice level of confidence on the advice you get (which, incidentally, you certainly aren't getting by reading this blog)

Friday, September 17, 2010

WPF, Prism, and Creating Dynamic Menus

This blog post originated from a question on StackOverflow How to programmatically set MenuItem.Header in a dynamic menu that I asked.  The first (and currently, only) person responding to the question implied that they weren't sure how I ended up where I did.  In order to clarify, I decided to write up this post (first one in what, a year?)

I've been working for sometime now on an application that utilizes WPF and Prism. Originally, the application had a static menu hosted in a seperate module - when the user clicked an item in the menu, static CompositeCommand objects would route command data back to a presentation model where DelegateCommands would handle the events.  This was an easy thing to knock together, as shown below.

The Original

PresentationModel

The original code behind the PresentationModel (or ViewModel - I started off with PresentationModel, even though VM is probably a better way of stating it - for consistency's sake, I'm going to stick with PM):



public interface IToolBarPresentationModel
{
   /// <summary>
   /// View associated with this model
   /// </summary>
   IToolBarView View { get; set; }
}

internal sealed class ToolBarPresentationModel : IToolBarPresentationModel
{
   private readonly IUnityContainer _container;
   private readonly IEventAggregator _eventAggregator;
   public DelegateCommand<object> FileExitCommand { get; set; }
   public DelegateCommand<object> HelpCommand { get; set; }

   /// <summary>
   /// Default constructor
   /// </summary>
   /// <param name="container">The unity container</param>
   /// <exception cref="ArgumentNullException">Thrown if the container is null</exception>
   public ToolBarPresentationModel(IUnityContainer container, IEventAggregator eventAggregator)
   {
      if (container == null)
         throw new ArgumentNullException("container", "The IUnityContainer cannot be null");
      if (eventAggregator == null)
         throw new ArgumentNullException("eventAggregator", "The IEventAggregator cannot be null");

      _container = container;
      _eventAggregator = eventAggregator;

      View = _container.Resolve<IToolBarView>();
      View.Model = this;

      FileExitCommand = new DelegateCommand<object>(new Action<object>(OnFileExit));
      HelpCommand = new DelegateCommand<object>(new Action<object>(OnHelp));

      ToolBarCommands.FileExit.RegisterCommand(this.FileExitCommand);
      ToolBarCommands.Help.RegisterCommand(this.HelpCommand);
   }
}

   private void OnFileExit(Object obj)
   {
      Application.Current.Shutdown();
   }

   private void OnHelp(Object obj)
   {
      var presentationModel = _container.Resolve<IHelpPresentationModel>();
      // Notify that the help view should be shown
      _eventAggregator.GetEvent<ChangeViewEvent>().Publish(new ChangeViewEventArguments(ViewName.HelpView));
   }

   #region IToolBarPresentationModel Members

   public Modules.ToolBar.Views.IToolBarView View
   {
      get;
      set;
   }

   #endregion
}

This is fairly straight-forward. We have two commands - File->Exit and Help, each of which have a static CompositeCommand that we add our DelegateCommand objects to. The Action targets exit the application, and call an event that forces the Help view to be displayed.

View

The original code behind simply implemented the View's interface:


public interface IToolBarView
{
   /// <summary>
   /// The model associated with this view
   /// </summary>
   IToolBarPresentationModel Model { get; set; }


The XAML was almost equally vanilla - except for one small detail that ended up being the crux of the problem:


<UserControl x:Class="Modules.ToolBar.Views.ToolBarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:Modules.ToolBar.PresentationModels"
xmlns:local="clr-namespace:Modules.ToolBar">
<Grid>
   <Menu Height="48" Margin="5,0,5,0" Name="MainMenu" VerticalAlignment="Top" Background="Transparent"
ItemsSource="{Binding}">
      <MenuItem Name="MenuFile" AutomationProperties.AutomationId="File">
         <MenuItem.Header>
            <StackPanel>
               <Image Height="24" VerticalAlignment="Center" Source="../Resources/066.png"/>
               <ContentPresenter Content="Main"/>
            </StackPanel>
         </MenuItem.Header>
         <MenuItem AutomationProperties.AutomationId="FileExit" Command="{x:Static local:ToolBarCommands.FileExit}">
            <MenuItem.Header>
               <StackPanel>
                  <Image Height="24" VerticalAlignment="Center" Source="../Resources/002.png"/>
                  <ContentPresenter Content="Exit"/>
               </StackPanel>
            </MenuItem.Header>
         </MenuItem>
      </MenuItem>
      <MenuItem Name="MenuHelp" AutomationProperties.AutomationId="Help" Command="{x:Static local:ToolBarCommands.Help}">
         <MenuItem.Header>
            <StackPanel>
               <Image Height="24" VerticalAlignment="Center" Source="../Resources/152.png"/>
               <ContentPresenter Content="Help"/>
            </StackPanel>
         </MenuItem.Header>
      </MenuItem>
   </Menu>
</Grid>
</UserControl>


The part of this XAML layout of the menu that I liked in the first cut was the appearance of each <MenuItem> - the <StackPanel> surrounding the <Image> and <ContentPresenter> lays out content such that it has sort of a "poor man's Ribbon" look and feel to it.

So: the goal is to keep the original look and feel of the menu, while updating it with the capability to have other modules add items to the menu.  The first cut!

Attempt One

So the first attempt had me adding a new model class that would represent a single item in the menu, called ToolbarObject - shown below.



/// <summary>
/// Represents an object on the toolbar
/// </summary>

public sealed class ToolbarObject : INotifyPropertyChanged
{

   public ToolbarObject() : this(String.Empty, String.Empty, null)
   {

   }
   public ToolbarObject(
      String name,
      String imageLocation,
      CompositeCommand command)
   {
      _name = name;
      _imageLocation = imageLocation;
      _command = command;
      Children = new ObservableCollection();
   }

   private String _name;
   public String Name
   {
      get { return _name; }
      set
      {
         _name = value;
         NotifyPropertyChanged("Name");
      }
   }

   private string _imageLocation;
   public String ImageLocation
   {
      get
      {
         return _imageLocation;
      }
      set
      {
         _imageLocation = value;
         NotifyPropertyChanged("ImageLocation");
      }
   }

   private CompositeCommand _command;
   public CompositeCommand Command
   {
      get
      {
         return _command;
      }
      set
      {
         _command = value;
         NotifyPropertyChanged("Command");
      }
   }

   private ObservableCollection _children;
   public ObservableCollection Children
   {
      get
      {
         return _children;
      }
      set
      {
         _children = value;
      }
   }
  
   #region INotifyPropertyChanged Members
      public event PropertyChangedEventHandler PropertyChanged;
   #endregion

   private void NotifyPropertyChanged(String name)
   {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (!String.IsNullOrEmpty(name)
         && handler != null)
      {
         handler(this, new PropertyChangedEventArgs(name));
      }
   }
}


Since I now have an object representing the menu, the PresentationModel was updated with an ObservableCollection of ToolbarItems - shown in the following (just showing the interface, as the implementation doesn't need explanation):



public interface IToolBarPresentationModel
{

/// <summary>
/// View associated with this model
/// </summary>

IToolBarView View { get; set; }

ObservableCollection<ToolbarObject> ToolbarItems { get; set; }

}


The view was updated to use a hierarchical data template, and the menu was bound to the data template and the new observable collection:


<UserControl x:Class="Modules.ToolBar.Views.ToolBarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:Modules.ToolBar.PresentationModels"
xmlns:local="clr-namespace:Modules.ToolBar">
   <UserControl.Resources>
      <model:ToolBarPresentationModel x:Key="modelData" />
      <HierarchicalDataTemplate DataType="{x:Type model:ToolbarObject}"
         ItemsSource="{Binding Path=Children}">
         <MenuItem Command="{Binding Path=Command}">
            <MenuItem.Header>
               <StackPanel>
                  <Image Height="24" VerticalAlignment="Center" Source="{Binding Path=ImageLocation}"/>
                  <ContentPresenter Content="{Binding Path=Name}"/>
               </StackPanel>
            </MenuItem.Header>
         </MenuItem>
      </HierarchicalDataTemplate>
    </UserControl.Resources>
<UserControl.DataContext>
    <Binding Source="{StaticResource modelData}"/>
</UserControl.DataContext>
<Grid>
   <Menu Height="48" Margin="5,0,5,0" Name="MainMenu" VerticalAlignment="Top" Background="Transparent"
ItemsSource="{Binding}">
   </Menu>
</Grid>
</UserControl>


This does a great job of rendering the first row in the menu - however, although the command routing works, the images are shown for the first items in the menu, any subitems aren't shown. Clicking on "File", for example, wouldn't collapse any submenu. In researching this, I came across two articles:

Building a Databound WPF Menu using a HierarchicalDataTemplate

WPF Sample Series - DataBound HierarchicalDataTemplate Menu Sample

In these examples, the code behind is responsible (in a load event) for constructing the hiearchy in the menu and ensuring that everything gets bound together correctly.  When this is just a menu, this works great - however, the moment you try to place the <StackPanel> into the <MenuItem.Header>, the whole thing doesn't get rendered (it is clickable, however).  The question on StackOverflow thus became the following:
  1. Admittedly, there is a "code-smell" in using the code-behind to construct what should just be a HierarchicalDataTemplate.  Is there a way to do this that doesn't involve the load event?
  2. If not, then how can you get the rendering of items placed into a MenuItem's Header to work?  What is preventing them from being drawn?
When I get more of a conclusion, I'll update this with the version that uses the advice in the menus and the actual solution (I'm confident there is a way to do this that isn't too ugly).  For now, the XAML and code-behind showing my version of the menu construction in the load event is available on the StackOverflow question here.

Sunday, January 17, 2010

Test 1 ... 2


public class Something
{
  private int _nSomethingElse;

  public Something()
  {
  }

  public int SomethingElse
  {
    get { return _nSomethingElse; }
    set { _nSomethingElse = value; }
  }
}