Contents tagged with WPF

  • 500 Metro Style WP7 Icons

    I was inspired by The Noun Project, a project that offers up “Metro-style” icons in SVG format. The project is licensed under a public domain license and while it’s a great project, all of the content is in SVG format. Jon Galloway has a great post (from 2007) talking about the differences between SVG and XAML so I highly recommend that for some background. I thought it would be helpful to the WPF/Windows Phone 7/Silverlight community to provide the content in alternative formats for use in your applications.

    The Goods

    I’ve put together a package of the 500 icons (502 actually) in PNG, XAML and the original SVG format along with a couple of sample projects so you can see them in action.

    There’s a WPF desktop app:

    500_icons_wpf

    And a Windows Phone 7 app:

    500_icons_windows_phone_7

    Building It

    To get all the content first I wrote up a quick program to suck the original SVG files. Luckily they’re all in a common path just named 1.SVG, 2.SVG, and so on. Easy sleazy to grab the contents. Once I had 500 SVG files I used the latest copy of XamlTune, an open source CodePlex project that has a command line conversion tool to convert the directory of SVG files into XAML (the tool also created a PNG file of each SVG so that’s just icing on the cake).

    Conversions

    The conversion from SVG to XAML isn’t 100%. While you can just drop the content into a WPF app, it doesn’t work that way for WP7. There are just some small adjustments I made to each format so you’ll have to do the same. Follow the information below or refer to the sample applications.

    As a sample, here’s an icon we want to use:

    10.xaml

    Here’s the original SVG file:

    <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
         width="100px" height="94.616px" viewBox="0 0 100 94.616" enable-background="new 0 0 100 94.616" xml:space="preserve">
    <path d="M25.076,15.639c4.324,0.009,7.824-3.488,7.82-7.82C32.9,3.512,29.4,0.012,25.076,0c-4.313,0.012-7.814,3.512-7.821,7.819
        C17.262,12.15,20.763,15.648,25.076,15.639L25.076,15.639z"/>
    <path d="M4.593,43.388h6.861l4.137-15.135h1.716L13.22,43.388h24.318l-4.389-15.135h1.817l2.32,7.415
        c1.08,3.131,3.852,3.851,6.003,1.162l8.375-10.142c2.651-3.42-2.104-7.021-4.844-4.035l-4.993,5.952
        c0.007,0.095-0.96-3.278-0.96-3.278c-1.135-3.978-4.918-7.903-10.595-7.922H19.576c-5.071,0.019-9.043,4.434-9.888,7.214
        L4.593,43.388L4.593,43.388z"/>
    <polygon points="56.206,22.753 56.206,7.163 49.192,7.163 49.192,22.753 56.206,22.753 "/>
    <path d="M79.87,15.738c4.332-0.014,7.831-3.516,7.82-7.82c0.011-4.332-3.488-7.833-7.82-7.82c-4.306-0.013-7.806,3.488-7.821,7.82
        C72.064,12.222,75.564,15.725,79.87,15.738L79.87,15.738z"/>
    <path d="M89.759,89.556v-43.19h5.751V22.804c0.007-3.079-2.757-5.448-6.71-5.449H70.436c-3.65,0.001-4.539,1.186-5.551,2.168
        L49.597,37.889c-3.098,3.848,2.428,8.333,5.55,4.743L69.88,25.226v64.43c-0.019,6.475,9.06,6.686,9.081,0.201v-36.58h1.765v36.379
        C80.748,96.109,89.772,96.13,89.759,89.556L89.759,89.556z"/>
    <polygon points="100,54.035 100,45.155 0,45.155 0,54.035 100,54.035 "/>
    </svg>
    

    Here’s the XAML that XamlTune created. It can be used in any WPF app without any changes:

    <Canvas Name="Layer_1" Width="100" Height="94.616" ClipToBounds="True" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <Path Fill="#FF000000">
    <Path.Data>
    <PathGeometry FillRule="Nonzero" Figures="M25.076,15.639C29.4,15.648 32.9,12.151 32.896,7.819 32.9,3.512 29.4,0.012 25.076,0 20.763,0.012 17.262,3.512 17.255,7.819 17.262,12.15 20.763,15.648 25.076,15.639L25.076,15.639z" />
    </Path.Data>
    </Path>
    <Path Fill="#FF000000">
    <Path.Data>
    <PathGeometry FillRule="Nonzero" Figures="M4.593,43.388L11.454,43.388 15.591,28.253 17.307,28.253 13.22,43.388 37.538,43.388 33.149,28.253 34.966,28.253 37.286,35.668C38.366,38.799,41.138,39.519,43.289,36.83L51.664,26.688C54.315,23.268,49.56,19.667,46.82,22.653L41.827,28.605C41.834,28.7 40.867,25.327 40.867,25.327 39.732,21.349 35.949,17.424 30.272,17.405L19.576,17.405C14.505,17.424,10.533,21.839,9.688,24.619L4.593,43.388 4.593,43.388z" />
    </Path.Data>
    </Path>
    <Path Fill="#FF000000">
    <Path.Data>
    <PathGeometry FillRule="Nonzero" Figures="M56.206,22.753L56.206,7.163 49.192,7.163 49.192,22.753 56.206,22.753z" />
    </Path.Data>
    </Path>
    <Path Fill="#FF000000">
    <Path.Data>
    <PathGeometry FillRule="Nonzero" Figures="M79.87,15.738C84.202,15.724 87.701,12.222 87.69,7.918 87.701,3.586 84.202,0.0849999999999991 79.87,0.097999999999999 75.564,0.084999999999999 72.064,3.586 72.049,7.918 72.064,12.222 75.564,15.725 79.87,15.738L79.87,15.738z" />
    </Path.Data>
    </Path>
    <Path Fill="#FF000000">
    <Path.Data>
    <PathGeometry FillRule="Nonzero" Figures="M89.759,89.556L89.759,46.366 95.51,46.366 95.51,22.804C95.517,19.725,92.753,17.356,88.8,17.355L70.436,17.355C66.786,17.356,65.897,18.541,64.885,19.523L49.597,37.889C46.499,41.737,52.025,46.222,55.147,42.632L69.88,25.226 69.88,89.656C69.861,96.131,78.94,96.342,78.961,89.857L78.961,53.277 80.726,53.277 80.726,89.656C80.748,96.109,89.772,96.13,89.759,89.556L89.759,89.556z" />
    </Path.Data>
    </Path>
    <Path Fill="#FF000000">
    <Path.Data>
    <PathGeometry FillRule="Nonzero" Figures="M100,54.035L100,45.155 0,45.155 0,54.035 100,54.035z" />
    </Path.Data>
    </Path>
    </Canvas>

    The XAML works AS-IS in a WPF application but there are some changes I did to get it to work in a WP7 app. Here’s the modified XAML in a WP7 application:

    <Canvas Grid.Row="0" Grid.Column="0"  Name="Icon_1" Width="100" Height="94.616">
        <Path Fill="#FF000000" Data="M25.076,15.639C29.4,15.648 32.9,12.151 32.896,7.819 32.9,3.512 29.4,0.012 25.076,0 20.763,0.012 17.262,3.512 17.255,7.819 17.262,12.15 20.763,15.648 25.076,15.639L25.076,15.639z">
        </Path>
        <Path Fill="#FF000000" Data="M4.593,43.388L11.454,43.388 15.591,28.253 17.307,28.253 13.22,43.388 37.538,43.388 33.149,28.253 34.966,28.253 37.286,35.668C38.366,38.799,41.138,39.519,43.289,36.83L51.664,26.688C54.315,23.268,49.56,19.667,46.82,22.653L41.827,28.605C41.834,28.7 40.867,25.327 40.867,25.327 39.732,21.349 35.949,17.424 30.272,17.405L19.576,17.405C14.505,17.424,10.533,21.839,9.688,24.619L4.593,43.388 4.593,43.388z">
        </Path>
        <Path Fill="#FF000000" Data="M56.206,22.753L56.206,7.163 49.192,7.163 49.192,22.753 56.206,22.753z">
        </Path>
        <Path Fill="#FF000000" Data="M79.87,15.738C84.202,15.724 87.701,12.222 87.69,7.918 87.701,3.586 84.202,0.0849999999999991 79.87,0.097999999999999 75.564,0.084999999999999 72.064,3.586 72.049,7.918 72.064,12.222 75.564,15.725 79.87,15.738L79.87,15.738z">
        </Path>
        <Path Fill="#FF000000" Data="M89.759,89.556L89.759,46.366 95.51,46.366 95.51,22.804C95.517,19.725,92.753,17.356,88.8,17.355L70.436,17.355C66.786,17.356,65.897,18.541,64.885,19.523L49.597,37.889C46.499,41.737,52.025,46.222,55.147,42.632L69.88,25.226 69.88,89.656C69.861,96.131,78.94,96.342,78.961,89.857L78.961,53.277 80.726,53.277 80.726,89.656C80.748,96.109,89.772,96.13,89.759,89.556L89.759,89.556z">
        </Path>
        <Path Fill="#FF000000" Data="M100,54.035L100,45.155 0,45.155 0,54.035 100,54.035z">
        </Path>
    </Canvas>
    

    All I did was take the data portion and put it directly into a Data attribute on the Path. Note that while it does show up in the app (on the emulator or device) it wouldn’t show up in Visual Studio for me. Maybe some XAML guru out there can tell me why. You can just as easily use the PNG files in WP7 but if you want the crispness of vector graphics, go for the XAML version.

    Of course with XamlTune being open source you could always modify the output of that program to cater it to your app. If you do make a change that’s worthy please consider submitting a patch to the project so everyone can benefit.

    Hope this helps and happy programming!

    Resources and Links

  • WPF Application Quality Guide, Revision 4 Released

    Microsoft has put together another version (this is rev 4) of their WPF Application Quality Guide, a fairly complete set of tasks and ideas around writing good quality apps using the Windows Presentation Framework.
     
    http://windowsclient.net/wpf/white-papers/wpf-app-quality-guide.aspx
     
    A few things to note:

    • I don't subscribe to the sample tests they provide and think they're a bit of a joke so squint your eyes when you read the guide. For example, according to ECMA-355 standards, a new operation can never fail yet they do silly things like Assert.IsNotNull(p) on the Person object. Awesome!
    • I would never name a test PersonConstructorTest1 and hope you don't think this is a recommendation.
    • The PersonConstructorTest2 is invalid as the assert will never get called. Again, this is not a best practice or even a guide on writing unit tests. It's supposed to show you concepts around it, but we're big boys and girls now and know better than this.
    • While it's considered a "guide" they mention "best practices" but don't call it that. I don't see any difference between "guide" and "best practice" and again, don't agree with some examples in this guide so you should apply some kind of nerd-filter to it in order to make it work for you and go read a real book on writing unit tests.

    Overall it's a good place to start when looking for resources on writing WPF apps and has some great links on real "Best Practices" for designers and developers. Check it out.

    (thanks to Greg and The Oren Machine for comments that I've incorporated into this post)

  • Building an Error Icon in WPF

    When you launch a XBAP application you can sometimes stumble over the XBAP error page which might look something like this:

    Here's a WPF user control that you can drop into any application that simulates the error icon you see. It's a simple Canvas control with two Grids and uses Paths and Elipses to define the graphical look.

    First create a new WPF User Control in your project or a library. Name it whatever you like, I called mine ErrorIcon. It'll be a type derived from UserControl so go into the XAML and change this to Canvas and also update the ErrorIcon.xaml.cs class to derive from Canvas instead of UserControl.

    <Canvas x:Class="WpfApplication1.UserControl1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Height="300" Width="300">

        <Grid>

     

        </Grid>

    </Canvas>

    namespace WpfApplication1

    {

        /// <summary>

        /// Interaction logic for UserControl1.xaml

        /// </summary>

        public partial class UserControl1 : Canvas

        {

            public UserControl1()

            {

                InitializeComponent();

            }

        }

    }

    Now drop in the following XAML code into your newly created Canvas:

    <Canvas x:Class="WpfApplication1.ErrorIcon" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Uid="ErrorCanvas" Margin="0,3,0,0" Width="44">

        <Grid Name="RedWarning" x:Uid="RedWarning" Width="44" Height="44" Visibility="Visible">

            <Ellipse x:Uid="Ellipse1">

                <Ellipse.Fill>

                    <LinearGradientBrush x:Uid="LinearGradientBrush14" StartPoint="0,0" EndPoint="0,1">

                        <LinearGradientBrush.GradientStops>

                            <GradientStopCollection x:Uid="GradientStopCollection4">

                                <GradientStop x:Uid="GradientStop32" Color="OrangeRed" Offset="0" />

                                <GradientStop x:Uid="GradientStop33" Color="DarkRed" Offset="1" />

                            </GradientStopCollection>

                        </LinearGradientBrush.GradientStops>

                    </LinearGradientBrush>

                </Ellipse.Fill>

                <Ellipse.Stroke>

                    <LinearGradientBrush x:Uid="LinearGradientBrush15" StartPoint="0,0" EndPoint="0,1">

                        <LinearGradientBrush.GradientStops>

                            <GradientStopCollection x:Uid="GradientStopCollection5">

                                <GradientStop x:Uid="GradientStop34" Color="transparent" Offset="0" />

                                <GradientStop x:Uid="GradientStop35" Color="#44ffffff" Offset="1" />

                            </GradientStopCollection>

                        </LinearGradientBrush.GradientStops>

                    </LinearGradientBrush>

                </Ellipse.Stroke>

            </Ellipse>

            <Ellipse x:Uid="Ellipse2" Opacity="0.5" Stroke="Transparent" Margin="1">

                <Ellipse.Fill>

                    <LinearGradientBrush x:Uid="LinearGradientBrush16" StartPoint="0,0" EndPoint="0,1">

                        <LinearGradientBrush.GradientStops>

                            <GradientStopCollection x:Uid="GradientStopCollection6">

                                <GradientStop x:Uid="GradientStop36" Color="white" Offset="0" />

                                <GradientStop x:Uid="GradientStop37" Color="transparent" Offset="1" />

                            </GradientStopCollection>

                        </LinearGradientBrush.GradientStops>

                    </LinearGradientBrush>

                </Ellipse.Fill>

            </Ellipse>

            <Path x:Uid="Path1" Stretch="Fill" Width="19.878" Height="19.878" StrokeThickness="5" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Data="M 200,0 L 0,200 M 0,0 L 200,200" />

        </Grid>

        <Grid x:Uid="RedReflection" Width="44" Height="44" Visibility="Visible" Canvas.Top="80" Canvas.Left="0">

            <Grid.OpacityMask>

                <LinearGradientBrush x:Uid="LinearGradientBrush20" StartPoint="0,1" EndPoint="0,0">

                    <GradientStop x:Uid="GradientStop44" Offset="0" Color="#3000" />

                    <GradientStop x:Uid="GradientStop45" Offset="0.9" Color="Transparent" />

                </LinearGradientBrush>

            </Grid.OpacityMask>

            <Grid.RenderTransform>

                <ScaleTransform x:Uid="ScaleTransform2" ScaleX="1" ScaleY="-0.85" />

            </Grid.RenderTransform>

            <Ellipse x:Uid="Ellipse3">

                <Ellipse.Fill>

                    <LinearGradientBrush x:Uid="LinearGradientBrush17" StartPoint="0,0" EndPoint="0,1">

                        <LinearGradientBrush.GradientStops>

                            <GradientStopCollection x:Uid="GradientStopCollection7">

                                <GradientStop x:Uid="GradientStop38" Color="OrangeRed" Offset="0" />

                                <GradientStop x:Uid="GradientStop39" Color="DarkRed" Offset="1" />

                            </GradientStopCollection>

                        </LinearGradientBrush.GradientStops>

                    </LinearGradientBrush>

                </Ellipse.Fill>

                <Ellipse.Stroke>

                    <LinearGradientBrush x:Uid="LinearGradientBrush18" StartPoint="0,0" EndPoint="0,1">

                        <LinearGradientBrush.GradientStops>

                            <GradientStopCollection x:Uid="GradientStopCollection8">

                                <GradientStop x:Uid="GradientStop40" Color="transparent" Offset="0" />

                                <GradientStop x:Uid="GradientStop41" Color="#44ffffff" Offset="1" />

                            </GradientStopCollection>

                        </LinearGradientBrush.GradientStops>

                    </LinearGradientBrush>

                </Ellipse.Stroke>

            </Ellipse>

            <Ellipse x:Uid="Ellipse4" Opacity="0.5" Stroke="Transparent" Margin="1">

                <Ellipse.Fill>

                    <LinearGradientBrush x:Uid="LinearGradientBrush19" StartPoint="0,0" EndPoint="0,1">

                        <LinearGradientBrush.GradientStops>

                            <GradientStopCollection x:Uid="GradientStopCollection9">

                                <GradientStop x:Uid="GradientStop42" Color="white" Offset="0" />

                                <GradientStop x:Uid="GradientStop43" Color="transparent" Offset="1" />

                            </GradientStopCollection>

                        </LinearGradientBrush.GradientStops>

                    </LinearGradientBrush>

                </Ellipse.Fill>

            </Ellipse>

            <Path x:Uid="Path2" Stretch="Fill" Width="19.878" Height="19.878" StrokeThickness="5" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Data="M 200,0 L 0,200 M 0,0 L 200,200" />

        </Grid>

    </Canvas>

    Bam! You've got an error icon that looks like this:

    To use it, just take any surface and add in a reference to the custom Canvas. Here it is in a pseudo-MessageBox like window:

    Enjoy!

  • Handling Unhandled Exceptions in XBAP Applications

    In your own applications you'll generally want a "catch-all" handler that will take care of unhandled exceptions. In WinForms apps this is done by creating an unhandled exception delegate and (optionally) creating an AppDomain unhandled exception handler. Peter Bromberg has a good article on all of this here and I wrote about the various options for WinForms apps here.

    With XBAP (XAML Browser Applications) the rules are slightly different so here's one way to do it.

    Take your existing XBAP app (or create a new one) and in the App.xaml.cs file you'll want to create a new event handler for unhandled exceptions. You can do this in the Startup method like so:

            protected override void OnStartup(StartupEventArgs e)

            {

                DispatcherUnhandledException += AppDispatcherUnhandledException;

                base.OnStartup(e);

            }

    In our exception handler, we'll do two things. First we'll set the exception to be handled and then we'll set the content of the MainWindow (a property of the Application class) to be a new exception handler page.

            private void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)

            {

                e.Handled = true;

                MainWindow.Content = new ExceptionHandlerPage();

            }

    That's really the basics and works. However you don't have the exception information passing onto the new page. We can do something simple for now. Here's the XAML for a simple error handling page:

    <Page x:Class="XbapExceptionHandlerSpike.ExceptionHandlerPage"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Width="300" Height="300"

        Title="ExceptionHandlerPage">

        <Grid>

            <Grid.RowDefinitions>

                <RowDefinition Height="23" />

                <RowDefinition />

            </Grid.RowDefinitions>

            <TextBlock Margin="10,0,0,0" VerticalAlignment="Center" Grid.Row="0" Text="An exception has occured. Here are the details:" />

            <TextBlock Margin="10,0,0,0" Grid.Row="1" x:Name="ErrorInformation" Foreground="Red" FontFamily="Consolas" TextWrapping="Wrap" />

        </Grid>

    </Page>

    I gave a name to the TextBlock in the second row in the grid. This is the control that will display our error message. I've also styled it and set the font to be a mono-spaced font.

    We can update our creation of the ExceptionHandlerPage class to include the exception details like so:

            private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)

            {

                e.Handled = true;

                var page = new ExceptionHandlerPage

                               {

                                   ErrorInformation = {Text = e.Exception.Message}

                               };

                MainWindow.Content = page;

            }

    Now our page displays the error with the details provided:

    Again, this is really simple and bare-bones. You can get creative with it with things like fancy fonts, dancing bears, floating borders, etc. and passing along the entire Exception (so you might walk through the inner exceptions and details) and even log the exception to your bug tracking system. Jeff Atwood has a great article on creating friendly custom Exception Handlers (one for WinForms here, one for ASP.NET here). A WPF version might be useful.

    As with WPF apps, there are a lot of ways to skin this cat. This is just my take on it. Feel free to offer your own twist.

  • Patterns, Practices, and Prism

    James Kovacs and I had the pleasure of presenting to a well fed crowd of about 150 crazed developers and IT folk at Shaw here in Calgary last night. We did a drive by discussion of Prism. I say drive by because we really just scratched the surface of what Composite Applications are all about (you can only do so much in 40 minutes on the subject) but we crammed in what we could. I hope it was a good intro to everyone and encourage you to head out and get Prism'd and see what the Patterns and Practices group has put together, it's a really great framework for building WPF based composite apps.

    Not this prism, but close...

    Thanks again to everyone who came out (even if it was for the food) and I had a blast presenting the content with James to you guys. Here's a copy of the slide deck if you're interested and here are a few key links from it:

    Thanks!

  • TechDays 08 - Mini Me version of TechEd, now with Canadian Content!

    Great news for Canadians! No, we haven't discovered a new source of unlimited clean-burning fuel and Stephen Harper is still our Prime Minister (for now).

    image

    Microsoft Canada has put together an awesome road show and it's coming soon. This is very much a mini-TechEd style conference but with a few twists. First off, it's Canadian based and will be hitting the major cities over the next couple of months. Second, some of the content is delivered by local freaks (such as myself) rather than the same old canned presentations by MSFT speakers. Don't get me wrong, the Canadian Developer support team (John Bristowe, Jean-Luc David, et. al.) are great but hey everyone has seen and heard them over and over again (and frankly Bristowes drag-n-drop sessions make me want to hurl). Now we can grab some premium air time and talk from the hip.

    Unlike the previous road show launches and sessions, this is a paid event. Wait, stick around. Okay, I understand and hear ya. Why buy the milk when I can get the cow for free? Here's some factoids to make your want to rush out and buy your Donald Belcham Secret Decoder Ring (and optional Justice Gray Hair Tonic Revitalizer). Rather than a single day, the event is spread out over 2 days (you can choose to attend a single day or both, your choice). In addition, there are over 30 technical sessions all on new technology (nothing old and crappy here, well maybe some old-ish stuff but not crappy) including Windows and Web development, Virtualization, and Infrastructure. There are also "birds-of-a-feather" type sessions and some after party geek fests going on. All in all, a pretty slick way to kill off two days in cold, cold winter (and that means you Winnipeg!).

    The two day conference is happening in the larger cities (Toronto, Montreal, Calgary, and Vancouver) with the one day conference happening in the less fortunate ones (Winnipeg, Halifax and Ottawa). The early bird price (before October 15) for one day is $124.99 or $249.99 for both days. After October 15th the price goes up to double at $249.99 and $499.99 respectively (so obviously if money is a concern I suggest you get in before October 15th). Space is limited to 5000 people so don't wait to sit out on this one.

    Swag? Did I mention the swag? Any conference worth it's salt needs swag and this one is no exception. Each attendee gets the following goodies:

    • 6-month TechNet Plus Subscription
    • Visual Studio 2008 Professional (full package)
    • Expression Web (full package)
    • Visual Studio 2008 Team Suite (eval)
    • Expression Studio (eval)
    • Virtualization Resource Kit
    • 30% off certification voucher (applicable to all MS Certification exams)
    • TechEd 2008 DVD Set (just like being there, except without the drinking)
    • $100 discount coupon for DevTeach/SQLTeach

    More? Oh yeah, I mentioned the presentations. I'm planning on presenting a whack of talks on WPF covering (Databinding, WinForms integration, CompositeWPF, LOB apps, etc.) so that should be fun. This is tentative as I haven't got the final word yet to take the stage (and after reading this blog post I may not be allowed to show up), but whatever happens I promise a) lots of code, no fluff b) flying monkeys c) Terrarium, Terrarium, Terrarium d) no concealed lizards or logging chains of any kind e) comic book cross-overs and f) did I mention the code? Beat those promise Mr. Harper!

    The TechDays website will be online soon with more details and registration info. You can find that here. You can also check out D'Arcys twisted take on this here, and Miguel's more calmer preview here.

    See you there!

    Technorati Tags:

  • Setting the Publish Status to Include for 3rd Party Files with XBAP deployments

    I was trying to deploy a new WPF app via XBAP today and we were experiencing an odd deployment error.

    When we deployed and launched the app we were getting this error:

    Startup URI: http://localhost/XbapNHibernateDeploymentSpike/XbapNHibernateDeploymentSpike.xbap
    Application Identity: http://localhost/XbapNHibernateDeploymentSpike/XbapNHibernateDeploymentSpike.xbap#XbapNHibernateDeploymentSpike.xbap, Version=1.0.0.5, Culture=neutral, PublicKeyToken=8c4ee06d2506bc6f, processorArchitecture=msil/XbapNHibernateDeploymentSpike.exe, Version=1.0.0.5, Culture=neutral, PublicKeyToken=8c4ee06d2506bc6f, processorArchitecture=msil, type=win32

    System.Runtime.Serialization.SerializationException: Unable to find assembly 'NHibernate, Version=2.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4'.

    This was odd because I knew that NHibernate.dll was being distributed with the app. I confirmed. There it was in the manifest file and in the deployment directory. Checking the Application Files settings inside of Visual Studio (this was just a test deployment, please don't deploy apps from inside Visual Studio) it was there and included:

    The generated manifest file showed it was included as well:

    <dependency>
        <dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="NHibernate.dll" size="1638400">
          <assemblyIdentity name="NHibernate" version="2.0.0.4000" publicKeyToken="AA95F207798DFDB4" language="neutral" processorArchitecture="msil" />
          <hash>
            <dsig:Transforms>
              <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
            </dsig:Transforms>
            <dsig:DigestMethod Algorithm="
    http://www.w3.org/2000/09/xmldsig#sha1" />
            <dsig:DigestValue>hUljboZ3kBAzBFbanjzLCJCMua0=</dsig:DigestValue>
          </hash>
        </dependentAssembly>
    </dependency>

    This didn’t make any sense. It was in the manifest, in the published directory, and everything looked like it should work. Google wasn’t much help here as I was in uncharted territory so I just starting poking around.

    Finally I came to the problem and a solution. The hibernate.cfg.xml file was being included as a data file and spec’d out in the manifest like this:

    <file name="hibernate.cfg.xml" size="604" writeableType="applicationData">
        <hash>
          <dsig:Transforms>
            <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
          </dsig:Transforms>
          <dsig:DigestMethod Algorithm="
    http://www.w3.org/2000/09/xmldsig#sha1" />
          <dsig:DigestValue>eICryxpUlz1ZHRpxHt+P2z8kBJo=</dsig:DigestValue>
        </hash>
    </file>

    Changing it from “Data File” to “Include” solved the problem.

    In the working version of the manifest file, the NHibernate config file is spec’d out as this:

    <file name="hibernate.cfg.xml" size="604">
        <hash>
          <dsig:Transforms>
            <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
          </dsig:Transforms>
          <dsig:DigestMethod Algorithm="
    http://www.w3.org/2000/09/xmldsig#sha1" />
          <dsig:DigestValue>eICryxpUlz1ZHRpxHt+P2z8kBJo=</dsig:DigestValue>
        </hash>
    </file>

    Note the difference in the file declaration. The non-working one includes an attribute: writeableType="applicationData"

    This is pretty obscure and maybe I’m just a simple guy, but telling me that you can’t find NHibernate.dll when you were really looking for a different isn’t very intuitive. Yes, I checked the stack trace, thinking that maybe the config file wasn’t there and it was an NHibernate exception being thrown or gobbled up, no such luck. The error was being reported out of PresentationHost.exe long before NHibernate was even being called.

    Don’t ask me why changing the Publish Status from Data File to Include fixes the issue, I just work here.

    Update: Sure enough, after you publish something on the internet along comes the information you were looking for. Buried somewhere on the web I found this tidbit:

    If you set the 'Publish Status' of the xml data file to "Data File", this file will reside in the Data directory in the end user's Local Settings folder after installation. If you set the 'Publish Status' of the xml data file to "Include", the file will be output to the Application directory.

    For xbap applications, the "Application directory" is the IE cache but when the Publish Status was set to "Data File" rather than "Include" it was going to nowhere land.

  • WPF for Business Applications, ready for the average user?

    We're starting a new project and naturally we looked at leveraging the latest .NET framework features (auto properties, extension methods, lamdas, LINQ, etc.). The question of user interface came up and we had some decisions to make.

    This specific project we looked at building one client web front-end (for the majority of the users) and a SmartClient for a smaller contigent that requires a little more real-time feel along with more rich features the web client might not be able to do (without a lot of heavy lifting). As we were looking to start things, the notion of WPF vs. WinForms came up. This led us down a path to look at Prism (the Composite WPF project from the Patterns and Practices group) which has a lot to offer in frameworks and being able to do more with WPF (Prism is WPF only). WPF also has some benefits to automation (there are some new products that are tying into the automation frameworks) and testing. The pretty UI is just an afterthought and not the focus since we're building what would be considered a "traditional" business application (forms and maybe grids and reports).

    WPF also has the advantage that we could deliver the application using xbap which kicks ClickOnce up a notch. The Prism framework is based on modules loading into XAML regions so we were even looking at re-using XAML user controls and plugging them into different clients.

    This has kicked off a bit of a controversy and discussion. Is WPF really suited to business applications? Of course the answer is (as always) it depends. If you're business application requires a rich UI and a visual paradigm, then the obvious answer is yes. It's more intuitive for a user to drag a part from one component to another (say in a room designer) than to pick items from a grid and enter values in a form.

    However for the larger business applications (the meat and potatoes of the corporate world) we don't deal with "rich UIs" so where does that leave you? WinForms is not dead and according to Glenn Block is the "recommended breadth solution for LOB application development in the foreseeable future". The trade off is that if you're building SmartClients you might look toward a framework that provides a lot of OOTB features that you don't have to do. I'm not a big fan of NIH syndrome and the idea of having to rewrite loggers, event handlers, aggregators, presentation models and everything else you build into a SmartClient. Frankly, I don't get paid to build frameworks or re-invent the wheel for every application my client wants.

    Prism provides a nice framework (IMHO CAB done right) that you can leverage and pull it out in piecemeal to what you need. Unfortunately, it's WPF only. While some of the principles can be carried over to WinForms I think you'll end up doing more work to say try to get DataBinding working the same way (if at all). There are other aspects to WPF (ignoring the pretty UI) that don't carry over to WinForms (routed events, event aggregation, etc.) all of which you have to build yourself (or use CAB which is the overbloated bazooka edition of WinForm programming).

    The word from my twitter folks is somewhat slighted toward WPF:

    • WPF databinding isn't as evil as its predecessors and some people wouldn't build a WPF app without it
    • Control templating and eventing in WPF is useful even for the basic forms and datagrids
    • Testable automations ARE good reasons to use it

    Other questions that come up:

    • Do you really need/want a separate designer to build your UI and keep it completely separate from your application code? In WPF this is easier. For WinForms you need to outfit them with Visual Studio and frankly, I've never used a designer on a WinForms project (I have on WPF ones, but not business applications)
    • What is the adoption from the user perspective and can you get them to think "outside of the form" and be creative with solutions. In WPF you're not as bound to traditonal approaches to visual problems and building the same solutions is somewhat easier (trust me, manipulating pixels in WinForms is a bugger to put a control on top of another one, in WPF it just works)
    • Can you bake the learning curve of WPF into a business application budget or should it be something that developers just know? (i.e. only start a WPF app when you have developers that know it inside and out, which few do these days)

    I’m on the fence on WPF. From an automation and programming model, I think it’s fathoms above WinForms. I don’t mind the crafting of a good looking UI as I’m used to it in Blend and can whip off a UI just as fast as I can with WinForms. However I’m not sure its worth the extra effort (is there extra effort) in building business applications with it, but I’m torn with xbap where we can deliver a rich user experience without having to install a client.

    For WinForms you generally have to either harvest what you have from existing applications or RYO when it comes to the application framework. Re-writing presenter base classes, validation strategies, various implementations of patterns like repository and specification, and building a service layer over things like NHibernate can be fairly straight forward but still might take a few weeks, weeks of cost that the customer doesn't want to pay for to see nothing out the other end.

    There is the build as you go model, which works for any technology however you do want to keep consistency when you're building 5+ large applications a year and there's turnaround in the IT department. Re-inventing the wheel for every application isn't an option for anyone.

    Feel free to chime in with your thoughts, experiences, and ideas. Thanks!

  • WPF or WinForms, choose wisely

    Choose, but choose wisely.WPF is all the rage (at least that's what they tell me) and it's IMHO one of the best technologies to come out of Microsoft. Still, however, companies choose to stay the course with building on WinForms. Karl Shifflett has a great blog entry on choosing WPF over ASP.NET (and great entries on WPF in general so check his blog out here). To me it's a no-brainer choosing WPF over ASP.NET, unless you're really enamored with a browser app (or forced to build one due to some constraints) and with Silverlight and XBAP (and the new features coming out shortly in Silverlight 2) building a rich interface for the web gets better and better. AJAX just doesn't cut it and is a hack IMHO.

    Making the decision between WPF and WinForms however is a different story. Sure, WPF is the new hotness and WinForms is old and busted but is it the right choice? Obviously "it depends" on the situation and Microsoft is continuing to deliver and support WinForms so it won't be going away anytime soon. So what are the compelling factors to choose WPF over WinForms? Karl hints at choices of WPF over WinForms in his WPF Business Application series, but the reasons might be subtle for some. 

    If you're struggling here are some reasons for choosing WPF over WinForms, and let's play devils advocate as you might have to fight for some of these.

    Latest Technology

    Why start new development on old technologies? There's bleeding edge (Silverlight 2 perhaps) and then there's cutting edge (WPF?) and we can probably start to talk about WinForms as legacy. Start, not come to that conclusion. WinForms development can be painful (much like moose bites) but the latest technology debate is a tough one. One on hand it's lickety-split to create WPF using the tools available today (see below) and from a development perspective WPF shines because everything is an object. The crazy hoops you have to jump through just to get an image on a button or menu are all but gone when you try embedding an object onto another one in XAML. On the flipside though, most of the large UI suites (DevExpress, Infragistics, Component One, Telerik) haven't fully completed their WPF implementations and the maturity lies in their WinForm incantations. Still, starting a new project today that might be delivered say 6-12 months from now doesn't make a lot of sense building on what some might consider legacy but as usual, you have to pick the right tool for the right job.

    Mature Product

    While WPF is pretty young in the eyes of consumers, Microsoft has invested 5+ years of development in it. WinForms arguably has the edge on maturity here (existing since the .NET 1.0 days) but don't knock WPF as a babe in the woods. It popped up on the R&D radar back in shortly after .NET 1.1 and Visual Studio 2003 came out and has been gestating ever since. This is a plus point if you're in a boardroom or meeting with some stuffies who think it's new and shiny but with no meat behind it. Combined with its own set of unique features, try something like UI automation and WinForms and we'll talk maturity. 10 years after WinForms was born and we're still struggling with UI automation. WPF solves this in one fell swoop, and does a nice job of it to boot.

    Silverlight

    WPF is based on XAML for it's definitions (both application code and UI design). Silverlight is the same because after all crunching down and serializing XML is dead simple these days. While Silverlight uses a subset of WPF for it's rendering, you can re-use a lot of what you might create in WPF and your application. This makes for building multiple UIs a happy-happy-joy-joy scenario. Too many times I've been faced with the problem of building a system for web users and desktop users. Too many times we've had to dumb down the web because it couldn't handle the rich experience the desktop provides, or be faced with 100k of JavaScript (yeah, try debugging that mess after a few sleepless nights) so anything has to be better than this. Silverlight lets you leverage a lot of your XAML investment you make in a WPF app and with technologies like BAML you can push the envelope even further. It's a win-win scenario for everyone and lays the smack down on Flash or Java anyday.

    Tools

    While we live in a domain driven design world (at least some of us do, you have come out of your cave right?) with objects and collections and tests oh my, there is still the UI to design. I'm not a huge fan of the move to CSS validated Expression Web, but I understand (and agree with) the choices Microsoft made with the model. Kicking it up a notch and delivering Expression Blend with it's integration into Visual Studio makes building WPF apps a breeze. In fact, I strongly advocate and support handing the UI design off to someone better suited to it. Let's face it, developers suck the big one at building UIs (unless it's "Hello World" with a big button and an image of Scott Hanselmans face on it) so let's let the UI designers design. Blend lets you do this by just letting the designers "go wild" as it were, without having to worry about "how in the heck am I going to hook this up later". Giving a designer a copy of Visual Studio to design a WinForm app is just plain crazy, and don't even try to convert their JPG mockups that have been signed off on into a Windows Form (been there, more t-shirts, I have a lot of them) but getting a XAML file from them just plugs right into our development environment and is dead simple to wire up to whatever back-end you have going at the time.

    UI Resolution

    How many bugs do you have logged on your current project that say something like "cannot see button x when my screen resolution is 800x600"? As a developer, we generally work at crazy resolutions that no sane person would run at (my current desktop runs at 1680x1050) so building forms on this just plain doesn't translate well (read: at all) to a users desktop of 800x600 or 1024x768. Buttons vanish, menu options disappear, and that oh so beautiful grid that is the lynchpin of your appplication is missing the bottom 20 rows and last 10 columns. Sure, WinForm containers and whatnot help but far too many times we forget about this and end up building things off in unseen areas of the screen. WPF doesn't solve this problem, but really helps. Not only that, we're not asking users to change the resolution or font size on their screen to see things clearly. In this day and age, users need to be able to dynamically change the system at will when they're working. I've seen users running with the extra large font theme as their eyes give out on them but apps just plain don't work well when your system font is 36pt Verdana. Look at the iPhone as an example of clever UI integration. It dynamically zooms in and out as you choose to make things readable. We need more of this on the desktop applications we build to suite the needs of users who want "to see it all" at once. WPF let's us do this with less pain than WinForms.

    Databinding

    WPF allows for much easier data binding through its model and this can result in faster development time. Now Unka Bil isn't telling you to go out and bind your WPF creations directly to ADO.NET models. I still live and die by Domain Driven Design so binding happens on objects (probably best through a Binding<T> adapter of your domain classes) but WPF does make it easier to do this if that's your thang.

    So overall it's a better experience, both from the development side and consumer side. Again, you might have some battles to fight with Corporate to jump onto the technology band-wagon, but this is might be a battle worth fighting for. WPF is no silver bullet (as I always harp, the is no silver bullet unless you're fighting werewolves) but hopefully this will help you make a more informed choice. The choice is yours, but choose wisely.

  • Automated UI Testing with Project White

    Try it, or else...A co-worker turned me onto Project White, an automated UI testing framework by ThoughtWorks. This along the same lines as NUnitForms and other automated systems. It's basically Selenium for WinForms (which rocks in its own right) so I thought I would dig more into White (it has support for WPF as well, but I haven't tried that out yet). It was good timing as we've been talking and coming up with strategies for testing and UI testing is a big problem (and it is everywhere else based on people I've talked to).

    The White library is nice and simple. All you really need to do is add in the Core.dll from White and your unit test framework and write some tests. I tested it with MbUnit but any framework seems to work. Ben Hall posted a blog entry about White along with some sample code. This, combined with the library got me started.

    As Ben did, I created a simple application with a single form and started to write some tests. I couldn't use Ben's complete sample as it was written for VS2008 and I only had VS2005 for my testing. No problem. You can use White with VS2005, but you'll need the 3.0 framework installed.

    I came across the intial problem with testing though. The first test that failed left the window up on the screen. This was an issue. I also wrote the same test Ben did, looking for a non-existant form, which appropriately threw a UIActionException. The test passed as it threw the exception I was looking for, but again the form was up on the screen. The Application.Kill() method wasn't being called if the test would fail or an exception was thrown. Ben's method was to put a call to Application.Kill in the [TearDown] method on the test fixture. This is great but I'm not a big fan of [SetUp] and [TearDown] methods. Another option was to surround each test with a try/catch/finally and in the finally code call out to the Application.Kill() method. This was ugly as I would have to do this on every test.

    Following Ben's example I created a WhiteWrapper class which would handle the White library features for me. I made it implement IDisposable so I could do something like this:

      1 using(WhiteWrapper wrapper = new WhiteWrapper(path))
      2 {
      3    ...
      4 }
      5 

    I also added a method to fetch me a control from the main window (using a Generic) so I could grab a control, execute a method on it (like .Click()) and check the result of another control (like a Label). Note that these are not WinForm controls but rather a White wrapper around them called UIItem. This provides general features for any control like a .Click method or a .Text property or items in a listbox.

    Here's my WhiteWrapper code:

      1 class WhiteWrapper : IDisposable
      2 {
      3    private readonly Application _host = null;
      4    private readonly Window _mainWindow = null;
      5 
      6    public WhiteWrapper(string path)
      7    {
      8        _host = Application.Launch(path);
      9    }
     10 
     11    public WhiteWrapper(string path, string mainWindowTitle) : this(path)
     12    {
     13        _mainWindow = GetWindow(mainWindowTitle);
     14    }
     15 
     16    public void Dispose()
     17    {
     18        if(host != null)
     19            host.Kill();
     20    }
     21 
     22    public Window GetWindow(string title)
     23    {
     24        return _host.GetWindow(title, InitializeOption.NoCache);
     25    }
     26 
     27    public TControl GetControl<TControl>(string controlName) where TControl : UIItem
     28    {
     29        return _mainWindow.Get<TControl>(controlName);
     30    }
     31 }
     32 

    And here are the refactored tests to use the wrapper (implemented via a using statement which makes using the library fairly clean in my test code):

      1 public class Form1Test
      2 {
      3    private readonly string _path = Path.Combine(Directory.GetCurrentDirectory(), "WhiteLibSpike.WinForm.exe");
      4 
      5    [Test]
      6    public void ShouldDisplayMainForm()
      7    {
      8        using(WhiteWrapper wrapper = new WhiteWrapper(path))
      9        {
     10            Window win = wrapper.GetWindow("Form1");
     11            Assert.IsNotNull(win);
     12            Assert.IsTrue(win.DisplayState == DisplayState.Restored);
     13        }
     14    }
     15 
     16    [Test]
     17    public void ShouldDisplayCorrectTitleForMainForm()
     18    {
     19        using (WhiteWrapper wrapper = new WhiteWrapper(path))
     20        {
     21            Window win = wrapper.GetWindow("Form1");
     22            Assert.AreEqual("Form1", win.Title);
     23        }
     24    }
     25 
     26    [Test]
     27    [ExpectedException(typeof(UIActionException))]
     28    public void ShouldThrowExceptionIfInvalidFormCalled()
     29    {
     30        using (WhiteWrapper wrapper = new WhiteWrapper(path))
     31        {
     32            wrapper.GetWindow("Form99");
     33        }
     34    }
     35 
     36    [Test]
     37    public void ShouldUpdateLabelWhenButtonIsClicked()
     38    {
     39        using (WhiteWrapper wrapper = new WhiteWrapper(path, "Form1"))
     40        {
     41            Label label = wrapper.GetControl<Label>("label1");
     42            Button button = wrapper.GetControl<Button>("button1");
     43            button.Click();
     44            Assert.AreEqual("Hello World", label.Text);
     45        }
     46    }
     47
    48 [Test] 49 public void ShouldContainListOfItemsInDropDownOnLoadOfForm() 50 { 51 using (WhiteWrapper wrapper = new WhiteWrapper(
    path, "Form1")) 52 { 53 ListBox listbox = wrapper.GetControl<ListBox>("listBox1"); 54 Assert.AreEqual(3, listbox.Items.Count); 55 Assert.AreEqual("Red", listbox.Items[0].Text); 56 Assert.AreEqual("Versus", listbox.Items[1].Text); 57 Assert.AreEqual("Blue", listbox.Items[2].Text); 58 } 59 } 60 }

    The advantage I found here was handling exceptions and unknown states. For example in the last test, ShouldUpdateLabelWhenButtonIsClicked I ran the test before I even had the controls on the form. The test failed but it didn't hang or crash the system. That's what the IDisposable gave me, a nice way to always clean up without having to remember to create a [TearDown] method.

    One of the philosophical questions we have to ask here is when is this kind of testing appropriate? For example, if I have good presenters I can test these kind of things with mocked out views and presenter/model tests. So am I duplicating effort here by testing the UI directly? Should I get my QA people to write these kind of tests? There's a long discussion to have in your organization around this so it's not just a "tool problem". You need to dig deep into what you're testing and how. At some point, you begin to divorce yourself from behaviour driven development and you end up testing UI edge cases and integration from a UI perspective. If your UI doesn't line up with your domain, how do you reconcile this? There are probably more questions than answers for this type of thing and software design is more art than science. The answer "it depends" goes a long way, but don't try to solve your business or design problems with a tool. There is no silver bullet here, just a few goodies to help you along the way. It's you who needs to decide what's appropriate for the situation and how much time, money, and resources you're going to invest in something.

    The library works pretty good and I'm happy with the test code so far. We'll have to see now how it deals with far more complex UIs (we have things like crazy 40-column grids with all kinds of functionality). Back later on how that goes. In the meantime, check out Project White here on CodePlex to help you with your automated UI testing.