Advanced WPF ListBox Scenario: Representing and Selecting an XML Hierarchy

July 22nd, 2010 by ryan No comments »

I’ve never found a use for the XmlDataProvider natively in Xaml for a shipping app, but today a @malevy had a situation that sounded interesting.  He has an Xml document structured as follows:

<Owners>

    <Owner name=”’”>

        <Pet name=”” />

        <Pet name=”” />

    <Owner name=””>

    …

</Owners>

He wanted to be able to represent this hierarchy in a ListBox, but actually select from the Pets.  Bonus points for the egregious expander as the owner container.  In the end it was a combination of XmlDataProvider pointing to the Pet nodes, a CollectionViewSource using a GroupDescription which walked up the XPath to Owner\@name, and the ListBox using an Expander as it’s GroupStyle container.

 

Here is what it looks like in the end:

image

 

Here’s the source.

ReSharper Test Runner and MSTest Projects

July 21st, 2010 by ryan No comments »

One of my biggest irritants with the Unit Testing ecosystem is that each runner does things a little different. Gallio has helped solve this to some extent, but even that hasn’t solved all the problems that come with content or resource file deployments, coverage settings, etc.  Gallio’s goal is noble if not arrogant, become the Runner to Rule Them All. 

Unlikely. 

ReSharper, on the other hand, has taken the Switzerland approach and tries to be true to each testing frameworks settings and run modes.  It has a gap in regards to MSTest at this point, though.  (Who uses MSTest you say?  Lots of people.  You wanted unit testing to become common place, remember?  Stop complaining.)  ReSharper gives you this nasty warning when running your MSTests with Code Coverage enabled.

image

See MSTest is actually pretty sweet when it comes to data capture.  It might not be blazing fast, but it lets you capture an awful lot of information in different situations.  In order to support those different situations nicely there is this file type called Test Settings (*.testsettings).  imageTest Settings files live in your solution folder and you can have a bunch of them.  In fact, Visual Studio 2010 gives you two by default: Local.testsettings and TraceAndTestImpact.testsettings. 

Local.testsettings doesn’t capture anything by default, but one of the first thing everyone tends to look for when running tests is code coverage.  Since Local.testsettings are their default and people don’t realize you can change your active test settings they open Local.testsettings, choose Data and Diagnostics and check Code Coverage (and probably other things that sound interesting).

Enable Code Coverage in Data and Diagnostics of Local.testsettings

Now you’ve eliminated Resharper as a Test Runner.  But you don’t have too!  Remember how I said you can have a bunch of those .testsettings files and eluded to the fact that one can be made Active.  Here’s what you’re going to do:

  1. Right click the Solution Items folder (don’t put them in a different solution folder, VS doesn’t like that, sorry).
  2. Click Add –> New Item
  3. Under Installed Templates (VS 2010) select Test Settings.
  4. Name the new file ReSharper.testsettings (or whatever makes you happy really) and click ok.

The Test Settings editor dialog will come up, but you don’t need to change a thing if you don’t want or need.  Data and Diagnostics will be empty which is good for ReSharper.  At this point, you can go to the Test menu option, open Select Active Test Settings and choose your new settings (ReSharper.testsettings in our example).

That’s it, use ReSharper all you like.  There are some other nice things that ReSharper will do for you in regards to abiding by deployment options for content files and things like that, but we’ll save that for a different day.  Here’s a quick video that highlights everything I’ve outlined here.

Event: TFS 2010 Overview, Scrum integration: June 22-23

May 19th, 2010 by ryan No comments »

[Updated: An offline, PDF agenda is available here]

Around a month from now Alexei Govorine of Quick Solutions and I will be leading a free, two day event diving into Team Foundation Server 2010 and its uses within a Scrum development organization.  This is my first year being a part of this event, but Alexei has a number of years under his belt now.  The agenda is quite aggressive, which will certainly be to the benefit of the audience.  I highly encourage those evaluating Team Foundation Server as well as those looking to get the most out of an existing Team Foundation Server deployment to come be part of this event.  An agenda is available below (offline PDF version here) and you can register here.

Agenda

Day 1 · June 22nd Day 2 · June 23rd
Keynote Development Practices
Business Value Overview Database Tools
Why Process Team Build
   
Lunch  
   
Team Explorer Test Manager
Project Management Reports
Architecture Tools Retrospective

 

If there are questions or you have topics you feel strongly about covering hit me up on Twitter @cromwellryan.

SketchFlow: From Concept to Production

April 16th, 2010 by ryan No comments »

I had a great time in Frankfort, KY yesterday.  We had a great turnout for the Expression SketchFlow: From Concept to Production session.  It is incredibly encouraging to see so many interested in building great, well designed apps for all industries and clients (even your LOB apps!).

Thanks again for those who made it.  You can find the slides and SketchFlow solution here.

Kentucky Briefings April 15th and 22nd

April 5th, 2010 by ryan No comments »

Along with a great cast of MS partners, evangelists, specialists and more I will be bringing Sketchflow to the Frankfort, KY area Thursday, April 15th.  This will be Session I with Session II scheduled for April 22nd.  You can learn about everything from Forefront Suite to Silverlight to Windows Phone 7 and, of-course, Sketchflow

You can find registration and session schedules in here (pdf).

Looking forward to seeing everyone there.

Grouping is crazy easy in WPF

March 18th, 2010 by ryan 1 comment »

Lots of people struggle with grouping data and when they do, the brut force method normally takes over and we start creating some crazy super structure to organize data and then do something like put a List inside of a List or a Grid inside of a list.  Just think of how many times you tried to put a GridView inside of a Repeater back when we didn’t know about jQuery or MVC and WebForms were all we knew.

Well it turns out WPF (and Silverlight 4.0) make this crazy easy.  It’s why the CollectionViewSource class exists.  The thing people don’t realize is that you don’t have to change anything about your data structure to make this work well (most times) and your designer (you have one right?) can make the decision on how best to display the information.

 

Step 1: Get Yourself Some Data

Don’t go crazy trying to group your data in your view model with Linq statements or anything like that.  You don’t (likely) need it.  Just get a list of your Animals with the necessary attributes for display in normal IEnumerable form.

Here’s how I’m doing to get my data for the sample:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <XmlDataProvider x:Key="data">
            <x:XData>
                <Animals xmlns="">
                    <Animal name="Dory" Species="Fish" />
                    <Animal name="Felix" Species="Cat" />
                    <Animal name="Fluffy" Species="Dog" />
                    <Animal name="Jake" Species="Snake" />
                    <Animal name="Mittens" Species="Cat" />
                    <Animal name="Murtle" Species="Turtle" />
                    <Animal name="Nemo" Species="Fish" />
                    <Animal name="Rex" Species="Dog" />
                    <Animal name="Rover" Species="Dog" />
                    <Animal name="Toonces" Species="Cat" />
                </Animals>
            </x:XData>
        </XmlDataProvider>
    </Page.Resources>
</Page>
Step 2: Group The Data with CollectionViewSource

We need to remember that Xaml is just a way to instantiate classes.  Knowing that, we can create a CollectionViewSource right in our xaml like this:

 

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <XmlDataProvider x:Key="data">
            <x:XData>
                <Animals xmlns="">
                    <Animal name="Dory" Species="Fish" />
                    <Animal name="Felix" Species="Cat" />
                    <Animal name="Fluffy" Species="Dog" />
                    <Animal name="Jake" Species="Snake" />
                    <Animal name="Mittens" Species="Cat" />
                    <Animal name="Murtle" Species="Turtle" />
                    <Animal name="Nemo" Species="Fish" />
                    <Animal name="Rex" Species="Dog" />
                    <Animal name="Rover" Species="Dog" />
                    <Animal name="Toonces" Species="Cat" />
                </Animals>
            </x:XData>
        </XmlDataProvider>
        <CollectionViewSource x:Key="animalsBySpecies" Source="{Binding Source={StaticResource data}, XPath=Animals/Animal}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="@Species" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Page.Resources>
</Page>

 

Step 3: Show The Data

This is where the fun happens.  We take something as simple as a ListView or, simplier yet, the ItemsControl and we hook it up to our CollectionViewSource like this:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <XmlDataProvider x:Key="data">
            <x:XData>
                <Animals xmlns="">
                    <Animal name="Dory" Species="Fish" />
                    <Animal name="Felix" Species="Cat" />
                    <Animal name="Fluffy" Species="Dog" />
                    <Animal name="Jake" Species="Snake" />
                    <Animal name="Mittens" Species="Cat" />
                    <Animal name="Murtle" Species="Turtle" />
                    <Animal name="Nemo" Species="Fish" />
                    <Animal name="Rex" Species="Dog" />
                    <Animal name="Rover" Species="Dog" />
                    <Animal name="Toonces" Species="Cat" />
                </Animals>
            </x:XData>
        </XmlDataProvider>
        <CollectionViewSource x:Key="animalsBySpecies" Source="{Binding Source={StaticResource data}, XPath=Animals/Animal}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="@Species" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Page.Resources>
    <DockPanel>
        <ScrollViewer DockPanel.Dock="Bottom" VerticalScrollBarVisibility="Auto">
            <ItemsControl ItemsSource="{Binding Source={StaticResource animalsBySpecies}}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding XPath=@name}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </DockPanel>
</Page>


This doesn’t give us anything we couldn’t do before:image 

So how do we represent this grouping? 

Step 3: Display the Grouping

Easy, we define the GroupStyle.  There is an awful lot we can do here, but we’ll go with putting each into a GroupBox with the Header being the Species.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <XmlDataProvider x:Key="data">
            <x:XData>
                <Animals xmlns="">
                    <Animal name="Dory" Species="Fish" />
                    <Animal name="Felix" Species="Cat" />
                    <Animal name="Fluffy" Species="Dog" />
                    <Animal name="Jake" Species="Snake" />
                    <Animal name="Mittens" Species="Cat" />
                    <Animal name="Murtle" Species="Turtle" />
                    <Animal name="Nemo" Species="Fish" />
                    <Animal name="Rex" Species="Dog" />
                    <Animal name="Rover" Species="Dog" />
                    <Animal name="Toonces" Species="Cat" />
                </Animals>
            </x:XData>
        </XmlDataProvider>
        <CollectionViewSource x:Key="animalsBySpecies" Source="{Binding Source={StaticResource data}, XPath=Animals/Animal}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="@Species" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Page.Resources>
    <DockPanel>
        <ScrollViewer DockPanel.Dock="Bottom" VerticalScrollBarVisibility="Auto">
            <ItemsControl ItemsSource="{Binding Source={StaticResource animalsBySpecies}}">
                <ItemsControl.GroupStyle>
                    <GroupStyle>
                        <GroupStyle.ContainerStyle>
                            <Style TargetType="{x:Type GroupItem}">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate TargetType="{x:Type GroupItem}">
                                            <GroupBox Header="{Binding Name}">
                                                <ItemsPresenter />
                                            </GroupBox>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </GroupStyle.ContainerStyle>
                    </GroupStyle>
                </ItemsControl.GroupStyle>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding XPath=@name}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </DockPanel>
</Page>


 

We’ve told WPF, take all of the Groups out of the CollectionViewSource and put each into a Container (just like it would with individual items), that container being a GroupItem instead of a ListItem.  Style the GroupItem such that its Template is a GroupBox with an ItemsPresenter inside to display each individual item.  You can do a lot with this and it also works with the GridView form of a ListView.

Source Control Smackdown 2009

December 7th, 2009 by ryan 1 comment »

With all the hubbub around Git, TFS 2010, and others over the last year or so, the Dayton .Net Developers Group is hosting a panel event this Wednesday, December 9th, titled Source Control Smackdown 2009.  I have been lucky enough to be selected to represent TFS in a clash against SVN (Justin Kohnen) and Git (Leon Gersing).  Please come down and share your experiences, learn some facts and enjoy the banter that will undoubtedly ensue.

Find directions, contact information, panel member bios and other details on the Dayton .Net Developers Group site.

Dog Food II: Implementing Scrum with TFS

November 13th, 2009 by ryan No comments »

I want to thank all of those who took time out of their day to hang out at the Dog Food II conference in Columbus.  Everything was a great success.  A special thanks to Danilo Casino, Brian Prince, Jeff Blankenburg and everyone else who helped put the event together. 

For those of you who attended my session on Implementing Scrum with Team Foundation Server, you can find my slides here.  I hope everyone enjoyed themselves and I’m already looking forward to getting started next year.

Strategy Pattern with Castle Windsor

October 30th, 2009 by ryan 2 comments »

One of the tangent patterns associated with isolation or Single Responsibility is the Strategy Pattern.  I use Castle Windsor as my IoC of choice and I had hoped there was some black magic built in to make the Strategy Pattern dead simple.  Turns out there is and there isn’t.

What is the Strategy Pattern

The strategy pattern is a way of isolating what would often be found in a case statement.  The bland example being calculating Sales tax on an Order.  Each state and/or country has its own tax calculation and rather than

   1: public void Process(Order order) {
   2:     switch(order.Country) {
   3:         case "USA":
   4:             order.Total = order.Subtotal * .07;
   5:             break;
   6:         case "Canada":
   7:             order.Total = order.Subtotal * .0985;
   8:             break;
   9:     }
  10: 
  11:     // ...
  12: }

you should be breaking each calculation out into different ITaxStrategy implementations and consuming them like so:

   1: public void Process(Order order) {
   2:     var strategy = _taxStrategyFactory.GetStrategyForOrder(order);
   3: 
   4:     var salesTax = strategy.CalculateSalesTax(order);
   5: 
   6:     order.SalesTax = salesTax;
   7:     order.Total = order.SubTotal + order.SalesTax;
   8: }

The question remains, how to eliminate the conditional logic in TaxStrategyFactory determining which strategy is chosen.  The solution is to set up a convention for discovering the available strategies and delegating the criteria to the Strategy itself.

Discovery

The concept here is that we don’t have to “hook up” any new Tax Strategy to our Processing mechanism, we just “publish” new ones in a known way and they are picked up simply based on their existence.  This is often referred to as Convention Over Configuration.  We accomplish this with Castle Windsor with the Fluent Registration API:

   1: container
   2:     .Register(AllTypes
   3:                   .FromAssembly(Assembly.GetExecutingAssembly())
   4:                   .Where(x => x.Name.EndsWith("Strategy"))
   5:                   .WithService.FirstInterface());

This will register all classes found in the executing assembly which have the suffix “Strategy” as implementing the ITaxStrategy interface.  The second half of convention based discovery is consuming the ITaxStrategy implementations.  We can want to get all of these into the TaxStrategyFactory via a constructor array dependency:

   1: public TaxStrategyFactory(params ITaxStrategy[] taxStrategies)
   2: {
   3:     _taxStrategies = taxStrategies;
   4: }

Unfortunately, Windsor doesn’t support arrays as dependencies by default.  Windsor has the concept of Resolvers (a strategy implementation itself) and we are going to have to tell it about the ArrayResolver which knows how to, err, resolve array dependencies:

   1: container
   2:     .Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel));

Cool, so put these all together in our registration code and we get:

   1: container
   2:     .Register(Component
   3:                   .For<IOrderProcessor>()
   4:                   .ImplementedBy<OrderProcessor>())
   5:     .Register(Component
   6:                   .For<ITaxStrategyFactory>()
   7:                   .ImplementedBy<TaxStrategyFactory>())
   8:     .Register(AllTypes
   9:                   .FromAssembly(Assembly.GetExecutingAssembly())
  10:                   .Where(x => x.Name.EndsWith("Strategy"))
  11:                   .WithService.FirstInterface());

At this point we can kick of the true discovery chain of events through:

   1: var processor = container.Resolve<IOrderProcessor>();
   2: 
   3: processor.Process(order);

Delegating Criteria

So in OrderProcessor.Process we are asked the TaxStrategyFactory for the applicable ITaxStrategy implementation:

   1: var strategy = _taxStrategyFactory.GetStrategyForOrder(order);
   2: 
   3: var salesTax = strategy.CalculateSalesTax(order);
   4: 
   5: //...

  The question is, how did the factory determine which of the boundless implementations applies?  That’s the job of each ITaxStrategy itself.  Here’s the implementation of our factory:

   1: class TaxStrategyFactory : ITaxStrategyFactory
   2: {
   3:     private readonly ITaxStrategy[] _taxStrategies;
   4: 
   5:     public TaxStrategyFactory(params ITaxStrategy[] taxStrategies)
   6:     {
   7:         _taxStrategies = taxStrategies;
   8:     }
   9: 
  10:     public ITaxStrategy GetStrategyForOrder(Order order)
  11:     {
  12:         return _taxStrategies.FirstOrDefault(x => x.IsApplicable(order));
  13:     }
  14: }

Notice how the TaxStrategyFactory depends on all of the ITaxStrategy implementations.  It then uses the ITaxStrategy.IsApplicable(Order) method as criteria for a FirstOrDefault call.  Here’s an example TaxStrategy for any Order with country “USA”:

   1: public class USTaxStrategy : ITaxStrategy
   2:     {
   3:         private static readonly IDictionary<string, double> TaxRates = new Dictionary<string, double>()
   4:                                                                    {
   5:                                                                        {"OH", 7.0},
   6:                                                                        {"MI", 6.25},
   7:                                                                    };
   8:         public double CalculateSalesTax(Order order)
   9:         {
  10:             var rate = TaxRates[order.State];
  11: 
  12:             return (order.SubTotal * (rate / 100));
  13:         }
  14: 
  15:         public bool IsApplicable(Order order)
  16:         {
  17:             return order.Country == "USA";
  18:         }
  19:     }

 

You can download the sample project that goes along with this here.

Dog Food II Registration Open

October 29th, 2009 by ryan 1 comment »

Registration has opened for the 2nd Annual Dog Food conference in Columbus, OH.  SDS is excited to be a sponsor and presenter this year and I hope you have a chance to come by and see some of the topics everyone has planned.  I plan to be there as an observer both days and a speaker the second.  You really need to be someone to get the final session on the final day (a Friday non-the-less), but it’s a topic I’m passionate about: Scrum with Team Foundation Server.

For an agenda and registration information, the venerable Jeff Blankenburg has made available the official Dog Food Conference site.