Determine Framework Version & Profile in a #NuGet Install.ps1

[Updated: @davidfowl suggested using the FrameworkName rather than parsing myself.  Thanks!]

I’m working on the Caliburn.Micro Nuget package and one of the things that we need is to add a default Bootstrapper, ShellView, and ShellViewModel to your project.  One awesome thing Rob Eisenberg has done is provide WPF, Silverlight and WP7 versions of Caliburn.Micro.  Unfortunately, the platforms are different enough that these three pieces we would like to add are different.

I say this is unfortunate only because Nuget doesn’t support framework and profile specific content through conventions.  That’s only available for binaries.  It does, however, provide hooks into the install process via PowerShell. 

Maybe you see where I’m headed…

The hard part for me was figuring out the framework version of the project targeted.  In the end, here’s how you can pull the TargetFrameworkMoniker in your install.ps1:

param($rootPath, $toolsPath, $package, $project)

  $moniker = $project.Properties.Item("TargetFrameworkMoniker").Value

  $framework= new-object System.Runtime.Versioning.FrameworkName($moniker)

  write-host "Identifier: " $framework.Identifier 
  write-host "Version: " $framework.Version
  write-host "Profile: " $framework.Profile

# WPF4 will be NETFramework,Version=v4.0,Profile=Client
# SL4 will be Silverlight,Version=v4.0
# WP7 will be Silverlight,Version=v4.0,Profile=WindowsPhone

Happy packaging!

Advanced WPF ListBox Scenario: Representing and Selecting an XML Hierarchy

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.

SketchFlow: From Concept to Production

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

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

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:

SNAGHTML5b58fce

 

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.

SNAGHTML5b5f65d