Thursday, November 27, 2008

XAML factoring


We are using the Infragistics Ribbon component in our application.  Our application has the same Ribbon Group content specified in multiple tabs.  I was looking for a way to share the group content so it wasn't copied and pasted in both locations.

I searched online and found a forum where one of their staff said it was not a feature.

This is not a problem as WPF allows you to share UI elements for compiled resource dictionaries.

When we compile XAML we get BAML stored inside the assembly as a resource.  This allows the x:Shared keyword to enable special functionality not available from C#.   Why not IL?  BAML is more compact than IL, can be localized after compilation, and is less of a security threat.

Specifying x:Shared in a resource dictionary means the content will be fetched new each time it is requested allowing the same user interface elements to be added in multiple places.

Here is an example:
    <Window.Resources>
        <StackPanel x:Key="moreContent" x:Shared="false">
            <TextBlock Text="local" />
        </StackPanel>
    </Window.Resources>
    <StackPanel>
        <StaticResourceExtension ResourceKey="moreContent" />
        <StaticResourceExtension ResourceKey="moreContent" />
    </StackPanel>
One may also put the shared content in another XAML file to share the resource with other XAML files in your application:
Window1.xaml

    <Window.Resources>
        <ResourceDictionary >
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Ribbon.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <StackPanel x:Key="moreContent" x:Shared="false">
                <TextBlock Text="local" />
            </StackPanel>
        </ResourceDictionary>
    </Window.Resources>
    <StackPanel>
        <StaticResourceExtension ResourceKey="moreContent" />
        <StaticResourceExtension ResourceKey="content" />
        <StaticResourceExtension ResourceKey="moreContent" />
    </StackPanel>

Ribbon.xaml:
    <StackPanel x:Key="content" x:Shared="false">
        <TextBlock Text="From Ribbon" />
    </StackPanel>
</ResourceDictionary>

Thursday, November 20, 2008

Clarity of intent and newing up structs

Sometimes it is useful to see if a struct hasn't been set.  Of course this can get you into trouble if the unset value is a legal value, but sometimes it's not, like when dividing an int 0 will throw.

Previously I had been using code like if (divisor != new int() ) to check the value prior to calling my function.

This struck me as very odd to be newing up a struct.

Then I recalled the default keyword, which I'd only used for generics before.  It turns out default works the same and declares intent better.

if (divisor != default(int) )
{

}

Of course in this contrived example it makes more sense to do != 0, but when more complex structs are involved the syntax works quite nicely.

Tuesday, November 11, 2008

Visual Studio Post-Build Events.

I haven't been a fan of Visual Studio Post-build command line events.

Problem:
We need to copy app.config during the build process and it needs to be mstest.exe.config in the test out directory.  During our Unit Testing process on the build server we've been referencing a static class to provide all of our configurations.  Now we are switching over to a real file.  This makes all the unit tests referencing our configurations fail because System.Configuration.ConfigurationManager.GetSection returns null.  The problem is our unit tests are being executed by MS test.  Ideally we would maintain a configuration class reading from a file and a configuration class for testing which uses test values.  Unfortunately due to time pressures that is not an option.

Solution:
By going into Visual Studio, project properties, Build Events Tab, Post-build event command line and typing copy "$(ProjectDir)app.config" "$(TargetDir)mstest.exe.config" /y
MSDN describes the $(ProjectDir) and $(TargetDir) variables
In our testrunconfig file we have a Deployment section and then a DeploymentItem with filename set to mstest.exe.config.  My frist thought was to do the file copy on our build server after getting the source files and then have our testrunconfig file copy the mstest.exe.config using a DeploymentItem.  Thinking about it for a minute I realized this would cause differences when we are building in Visual Studio and when we are building on the server which would easily cause confusion in the future.

Not to happy we are relying on the filesystem for our test, but happy that the build behaves the same on desktops and servers and anyone can figure out what is going on.