Welcome to irritatedVowel.com Sign in | Help

POKE 53280,0: Pete Brown's Blog

Silverlight, WPF, Windows Client Development, Woodworking, .NET Programming, CNC, Nature, and other topics.

Subscribe

Subscribe to my feed
Add to Technorati Favorites

My Book

Order my upcoming book, Silverlight in Action, covering Silverlight 4, ViewModel/MVVM, WCF RIA Services, MEF and more

About Pete Brown

Pete Brown is a Microsoft Developer Division Community Program Manager, focusing on Windows Client Development as well as a former Microsoft Silverlight MVP and INETA Speaker. Pete writes on a number of topics including Silverlight, WPF, .NET, woodworking and working as a consultant in the DC area. read more

Community Events


who's online

AddThis Social Bookmark Button

Tip: New .NET 4 String Function to Check for Empty Strings

How many times have you written code similar to this?

string firstName = FirstName.Text.Trim();

if (!string.IsNullOrEmpty(firstName))
{
    // do something
}

or

if (someParam == null || string.IsNullOrEmpty(someParam.Trim())
    throw new ArgumentException("Empty string", "someParam");

// do something

A nice little time-saver for those guard functions is now included in .NET 4: the IsNullOrWhiteSpace function:

if (!string.IsNullOrWhiteSpace(FirstName.Text))
{
    // do something
}

IsNullOrWhiteSpace checks for null, empty or whitespace characters.

Sure, it’s a little thing, but it’s nice to have it in there, especially considering we get all sorts of nice new little things, and the client framework install is still smaller than it was in .NET 3.5

Getting Started with WPF : Hello World in multiple flavors

So you’re brand spanking new to WPF. You have to start somewhere, so how about good old “Hello World”.

Tooling

First, some tooling. If you are in a situation where you can use Beta or RC products, download Microsoft Visual Studio 2010 RC. I’m still using the Beta, as the RC came out today and doesn’t yet support Silverlight 4.

If you can’t use a Beta or RC, use Visual Studio 2008. Some caveats: many in the community have lamented the state of the WPF design surface in 2008, so it may not be very usable to you outside of typing in plain xaml. Also, VS2008 can only work with WPF 3.5sp1; it won’t work with WPF4. VS2010 can run with both.

My examples below will be in VS2010 with WPF 4, but you can follow along in either. You can get Visual Studio 2010 here.

Creating the Project

Visual Studio 2010 presents you with the Start page when you open it up. This page provides quick access to recently opened projects, as well as information on how to get started in various technologies.

image

After you close the start page, you can always get back to it by choosing View->Start Page

image

Select the “New Project” item from the left of the Start Page (or File->New->Project). You’ll get the “New Project” dialog

image

The New Project dialog has a lot going on in it, so let’s take a moment to explain what’s there. On the far left, you’ll see all the different types of applications your current installation of VS is able to build. Depending upon the edition you are using, and the add-ons you have installed, this list will vary.

I generally code in C#, so I’ll pick the “Windows” category under C#. The middle pane fills up with all the project templates for Windows application development. The framework selection drop down (top left in middle pane) shows all the different frameworks my installation is able to build against. I like the latest and greatest, so I’m using .NET Framework 4 (currently in RC – beta 2 in use in my example)

The right pane shows the description of what you’ve selected in the middle pane. We’ll get to the bottom pane in a moment.

In the middle pane, select “WPF Application”. This is a Windows Presentation Foundation windows application. The other templates are for other WPF supporting libraries, console applications, windows service, and windows forms applications.

Once you select the type of application you want to build, you can then give it a name. I’ll call mine “PeteBrown.WpfHelloWorld”. I typically prefix projects with the company name or my own name, as appropriate.

I usually keep the solution name set to something that makes sense solution-wide. Since we’re doing a simple Hello World, you can leave it as-is.

image

Hit OK to create your project. Visual Studio will take the templates and the parameters you’ve supplied (name, location, solution name) and build out the solution for you. The end result will look something like this:

image

For this example, we’ll deal primarily with MainWindow.xaml

Startup Window

The Main Window is the window that is, by default, displayed when your application starts up. What determines that? It’s the entry in App.xaml

<Application x:Class="PeteBrown.WpfHelloWorld.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

If you change the name of your main window, you’ll want to change it there as well.

Main Window

MainWindow.xaml, as mentioned above, is the main window for your application. You can add as many windows as you want, but we’ll do our Hello World example using just the single window.

The default content for MainWindow.xaml is a Window definition with an empty content grid. The Grid is one of many types of panels. It is one of the most powerful panels because it supports table-like subdivision (via ColumnDefinition and RowDefinition elements) as well as automatic stretching of content.

<Window x:Class="PeteBrown.WpfHelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <!-- This is where your content goes -->
    </Grid>
</Window>

The first thing we want to do is change the title of the window. Where it says Title=”MainWindow”, replace that to say Title=”My First WPF Application”. You can do that either directly in the xaml, or via the property pane in Visual Studio.

image

As a straight “hello world” would make for a short post with little to teach, I thought we’d take a few different approaches.

Hello World 1: All in Xaml

The basic element you’ll use for displaying text on the screen is the TextBlock. In the grid tags, add this line of markup:

;"><Window x:Class="PeteBrown.WpfHelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My First WPF Application" Height="350" Width="525">
    <Grid>
        <TextBlock Text="Hello World!" />
    </Grid>
</Window>

The resulting window, in the designer, will look like this:

image

Cool, but I think it would look nicer if we made it a larger font and centered it in the window:

<Window x:Class="PeteBrown.WpfHelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My First WPF Application" Height="350" Width="525">
    <Grid>
        <TextBlock Text="Hello World!"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   FontSize="50"
                   FontWeight="Bold"/>
    </Grid>
</Window>

image

How about we do some more things with this? Maybe twist it around a little

Hello World 2: Transformed

Sure, that was easy to do, but how about we rotate and scale it a little?

<Window x:Class="PeteBrown.WpfHelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My First WPF Application" Height="350" Width="525">
    <Grid>
        <TextBlock Text="Hello World!"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   FontSize="50"
                   RenderTransformOrigin="0.5,0.5"
                   FontWeight="Bold">
            <TextBlock.RenderTransform>
                <TransformGroup>
                    <ScaleTransform ScaleX="1.25"
                                    ScaleY="4" />
                    <RotateTransform Angle="-15" />    
                </TransformGroup>
            </TextBlock.RenderTransform>
        </TextBlock>
    </Grid>
</Window>

image

Pretty neat, eh? We’re doing a few interesting things in this example. First, we added the RenderTransformOrigin property to the TextBlock declaration. That says that any render transforms (like scale, rotate etc.) should be centered on the textblock (0.5, 0.5 is center on a 0 to 1 scale)

Secondly, we opened up the TextBlock tag so it could contain nested tags and added a TransformGroup. What’s with that <TextBlock.RenderTransorm> syntax, though? That’s simply the expanded property element synax. Each property of an element can be written that way. Some, like Text, for example, can also be written as a simple attribute (Text=”Foo”). When you need to nest other elements, you need to use the expanded property element syntax.

Inside the RenderTransform property, we added a TransformGroup. If you were only doing a single transform, you wouldn’t need a group. We’re doing two transforms, though, so we need to enclose them in a group.

Finally, inside the TransformGroup, we added a ScaleTransform and a RotateTransform. Scale is set to 1.0 is the natural size of the element; anything higher is bigger, anything lower is smaller.

That’s it for monkeying around. Let’s keep going.

Hello World 3: All in Xaml, with Scaling

Starting back at our TextBlock, without render transforms, let’s working on scaling it. One way to scale content in WPF is to use a ScaleTransform as we saw above. Another way to handle scaling with little to no effort on your part is to use a ViewBox.

A ViewBox scales content to take up all available space while (by default) retaining its aspect ratio.

<Window x:Class="PeteBrown.WpfHelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My First WPF Application" Height="350" Width="525">
    <Grid>
        <Viewbox>
            <TextBlock Text="Hello World!"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       FontSize="50"
                       RenderTransformOrigin="0.5,0.5"
                       FontWeight="Bold">
            </TextBlock>
        </Viewbox>
    </Grid>
</Window>

image

Let’s run it and resize the window to see what it looks like

image

image

image

Pretty nice. Our content was smoothly scaled and we didn’t have to do a thing other than include the ViewBox element. This works with more than just text, you can use it for entire user interfaces. Rather than, say, run a visually impaired person’s monitor at 800x600 and have them look at all that blocky low-res UI all day, you can design your app to scale up and provide a very smooth high-DPI version suited for those users. The result is night and day.

So what does ViewBox do? It uses a ScaleTransform on all contained content.

Hello World 4: Set from Code-Behind

For this next example, we’ll add a button to our window, so we’ll need to play with the markup a little. We’ll keep the ViewBox just to show that you can continue to scale the content, but we’ll nest a grid inside it and add a couple buttons.

<Window x:Class="PeteBrown.WpfHelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My First WPF Application" Height="350" Width="525">
    <Grid>
        <Viewbox>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                
                <TextBlock x:Name="GreetingText"
                           Grid.Row="0"
                           Text="Hello World!"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           FontSize="50"
                           RenderTransformOrigin="0.5,0.5"
                           FontWeight="Bold">
                </TextBlock>

                <TextBox x:Name="FirstName"
                         Grid.Row="1"
                         Text="Pete"
                         FontSize="25"
                         Margin="10"
                         Height="45" />

                <Button x:Name="GreetMeButton"
                        Width="100"
                        Height="45"
                        Grid.Row="2"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Bottom"
                        Content="Greet me!" />
            </Grid>
        </Viewbox>
    </Grid>
</Window>

Here are the changes made to the window contents

  • Added three rows to the grid (Grid.RowDefinitions). They are set to Auto size, so they’ll be as tall as they need to be to show the content
  • Added a x:Name to each control. When you use x:Name, you can refer to your controls by name in the code-behind.
  • Added a TextBox named FirstName
  • Added a Button named GreetMeButton
  • Set the Grid.Row attached property for each of the controls so they go into the proper grid row (Grid.Row is zero-based)

Here’s what the result looks like in the designer:

image

Now we need to add some code. The idea is, you type your name into the name field, hit “Greet Me” and the text will change to say “Hello, [Name]!” like “Hello, Pete!”

Double-click the button in the designer to generate an event handler for the button click.

<Button x:Name="GreetMeButton"
        Width="100"
        Height="45"
        Grid.Row="2"
        HorizontalAlignment="Center"
        VerticalAlignment="Bottom"
        Content="Greet me!"
        Click="GreetMeButton_Click" />

There are a few other ways you can go about this, like typing Click=” in the xaml and letting Visual Studio generate the handler and markup, or by manually wiring up the event handler in the code behind.

private void GreetMeButton_Click(object sender, RoutedEventArgs e)
{
    if (!string.IsNullOrWhiteSpace(FirstName.Text))
    {
        GreetingText.Text = 
            string.Format("Hello, {0}!", FirstName.Text);
    }
}

The code simply does an assignment of the GreetingText (TextBlock) Text property to be the string specified in the format statement. Note the guard code that first checks to see if the string is empty. The IsNullOrWhiteSpace function is new to .NET 4.

Run it, type your name into the textbox and click the button.

image

An interesting side-effect of using a ScaleTransform on the whole thing and not constraining the size of the content inside the transform is that if you type a really long name, the UI will shrink to accommodate it.

image

Next step is to do this with control-to-control (UI) binding.

Hello World 5: UI Binding

What if we could do the same thing without requiring any code? WPF (and Silverlight) provides the ability to bind the value of a property on one control to a property on another. As is always the case with binding, there are some restrictions: notably that the property that is the binding target (the property getting the value) needs to be a dependency property. If it isn’t, and you try to bind, you’ll get a runtime error.

Taking the same markup from our last example, we’ll remove the Click=GreetMeButton_Click” event handler wireup from the button and add in the binding statement. Removing the handler isn’t strictly necessary, but I want to make sure the value is coming from binding and not have too many pieces in play.

Then update the TextBlock’s Text property to get its value from binding:

<TextBlock x:Name="GreetingText"
           Grid.Row="0"
           Text="{Binding Text, ElementName=FirstName, StringFormat='Hello, \{0\}!'}"
           HorizontalAlignment="Center"
           VerticalAlignment="Center"
           FontSize="50"
           RenderTransformOrigin="0.5,0.5"
           FontWeight="Bold">
</TextBlock>

The binding statement says “From the element with x:Name FirstName, take the value of the Text property and insert it as {0} in the String Format “Hello, {0}!”. The {} have to be escaped with a \ because they are also the opening and closing symbols for markup extensions, of which binding is one.

Run the application and notice how the UI updates in real-time based on what you type in the textbox. You can use this same concept to provide things like character counts (by binding a textblock to the .Text.Length property). It also works well to do things like bind textboxes to sliders to display the numeric value, bind sliders to rotation and scale transforms etc.

As powerful as UI binding is, more often, you’re going to be doing data binding to other classes.

Hello World 6: “Data” Binding

I use “Data” in quotes because I think data binding conjures up bad memories of recordsets, open table cursors, and vcr controls for many of us. Trust me, in WPF (and Silverlight) binding is the way you’ll get almost all your UI –>data->UI updating and display done. If you find yourself writing a lot of someUIELement.Text = myObject.LastName type code, you’re probably doing it wrong.

If you’re looking for one thing to spend time learning inside and out in WPF, it’s binding.

I won’t get into specific patterns here (like ViewModel/MVVM, MVP, SC etc.) but I’ll show how to create a data class to hold our name, and use that in binding.

First, the class to hold the info. I’ll add a couple extra properties just to make it look normal, but we’ll only use FirstName for now.

Add a new class (named Person) to your project.

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Next, in the code-behind for our window, let’s create an instance of the Person class and assign it as the “Data Context” of the window. The DataContext property is the root of all binding. All binding statements will be relative to it. Typically DataContext is a high-level object like a Customer, or in the case of the ViewModel pattern, the ViewModel itself.

public MainWindow()
{
    InitializeComponent();

    Person person = new Person() 
        { 
            LastName = "Brown", 
            FirstName = "Pete" 
        };

    this.DataContext = person;
}

Next, we need to bind the TextBox so that it displays and updates the FirstName property of the Person object that is our DataContext:

<TextBox x:Name="FirstName"
         Grid.Row="1"
         Text="{Binding FirstName, Mode=TwoWay}"
         FontSize="25"
         Margin="10"
         Height="45" />

We want the textbox to both read and write to the FirstName property, so we set the binding mode to TwoWay. If you leave that out, it will typically default (depends on the property) to OneWay, which means effectively a read-only binding.

Next, we need to update the TextBlock to display the value from the FirstName property. We’ll keep the string format intact, but remove the element binding.

<TextBlock x:Name="GreetingText"
           Grid.Row="0"
           Text="{Binding FirstName, StringFormat='Hello, \{0\}!'}"
           HorizontalAlignment="Center"
           VerticalAlignment="Center"
           FontSize="50"
           RenderTransformOrigin="0.5,0.5"
           FontWeight="Bold">
</TextBlock>

The textblock’s binding doesn’t need to specify TwoWay since it will be read-only. It also doesn’t need to specify OneWay since that is the default. The StringFormat is the same one we had earlier, and the same format used when we had code-behind.

Like the previous example, other than the creation of the Person object and setting DataContext, this example has no code-behind. Similarly, the button is unnecessary. What you may notice, though, is unlike the previous example, this one only updates when you tab off the field. Typically, that’s the behavior you’d want (you don’t want to update a business entity with every keystroke), but you can control that.

The UpdateSourceTrigger (which defaults to LostFocus) can be set to PropertyChanged to invoke the binding update with each keystroke.

<TextBox x:Name="FirstName"
         Grid.Row="1"
         Text="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
         FontSize="25"
         Margin="10"
         Height="45" />

Great, now what if we want to get both the First and Last names into that greeting text?

Hello World 6.1: Multi Binding

Multi-binding is something that is not used often in WPF, but when you need it, you need it. Multi-binding provides a way to combine the output of two or more source properties into a single target property. In our case, we’re going to use it to combine first and last name in the greeting text.

Back to some UI updates. We now want to capture both first and last name in textboxes, so we’ll get rid of our button and add a Last name text box in its place. The resulting UI xaml looks like this:

<Window x:Class="PeteBrown.WpfHelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My First WPF Application" Height="350" Width="525">
    <Grid>
        <Viewbox>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />

                </Grid.RowDefinitions>
                
                <TextBlock x:Name="GreetingText"
                           Grid.Row="0"
                           Text="{Binding FirstName, StringFormat='Hello, \{0\}!'}"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center"
                           FontSize="50"
                           RenderTransformOrigin="0.5,0.5"
                           FontWeight="Bold" />

                <TextBox x:Name="FirstName"
                         Grid.Row="1"
                         Text="{Binding FirstName, Mode=TwoWay}"
                         FontSize="25"
                         Margin="10"
                         Height="45" />

                <TextBox x:Name="LastName"
                         Grid.Row="2"
                         Text="{Binding LastName, Mode=TwoWay}"
                         FontSize="25"
                         Margin="10"
                         Height="45" />

            </Grid>
        </Viewbox>
    </Grid>
</Window>

That’s our starting point. Notice that both textboxes are wired up as required. They both have names, but that’s not actually necessary since we’re never referring to them in code. Speaking of code, our code is the same as the previous example – just setting the DataContext to an instance of the Person class.

Before we get into multi-binding, let’s take a quick detour into the Property Element syntax for regular binding. The curly brace syntax we’ve been using so far is the nice markup extension syntax. That makes it quick and easy to write binding statements without having to break everything out. VS2010 even includes intellisense for the extension.

However, we could have written the binding like this:

<TextBlock x:Name="GreetingText"
           Grid.Row="0"
           HorizontalAlignment="Center"
           VerticalAlignment="Center"
           FontSize="50"
           RenderTransformOrigin="0.5,0.5"
           FontWeight="Bold">
    <TextBlock.Text>
        <Binding Path="FirstName"
                 StringFormat="Hello, {0}!" />
    </TextBlock.Text>
</TextBlock>

While more verbose, it is equivalent to this:

<TextBlock x:Name="GreetingText"
           Grid.Row="0"
           Text="{Binding FirstName, StringFormat='Hello, \{0\}!'}"
           HorizontalAlignment="Center"
           VerticalAlignment="Center"
           FontSize="50"
           RenderTransformOrigin="0.5,0.5"
           FontWeight="Bold" />

Now that you know how to break out the binding statement, it’s time for multi-binding. We’re going to use multi-binding to get FirstName and LastName into our textblock.

<TextBlock x:Name="GreetingText"
           Grid.Row="0"
           HorizontalAlignment="Center"
           VerticalAlignment="Center"
           FontSize="50"
           RenderTransformOrigin="0.5,0.5"
           FontWeight="Bold">
    <TextBlock.Text>
        <MultiBinding StringFormat="Hello, {0} {1}!">
            <Binding Path="FirstName" />
            <Binding Path="LastName" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

Note the stringformat is on the MultiBinding itself, and it respects the position of both of our binding values, passing them in as {0} and {1}. Very slick.

If you run the application now, you’ll see something like this:

image 

Where to go from here?

I hope that gives you a taste of how to do some basic things in WPF. There’s a lot more to learn, but once you get the basics of UI structure, event handling, and binding down, everything else is just details :)

Check out http://windowsclient.net/learn for lots of great tutorials. Visit the forums, try the sample applications, and of course, subscribe to my blog and follow me on twitter.

 

Have fun!

Windows Client Developer Roundup for 2/8/2010

This is Windows Client Developer roundup #10.

The Windows Client Developer Roundup aggregates information of interest to Windows Client Developers, including WPF, Surface, Windows 7, XNA, Windows Forms, and some Silverlight. If you have something interesting you’ve done or have run across, please send me the URL and brief description via the contact link on my blog.

WPF

XNA

Surface

Cross-Technology (WPF, Silverlight, Surface etc.)

Silverlight

C++ / Native Windows Code

Fun

Creating Customized UserControls (Deriving from ContentControl) in WPF 4

Another twitter question. As usual, I’m targeting WPF 4 here, but just about everything here works with Silverlight 4 as well.

image

(read from bottom up)

Let’s say you want to create a standardized “gadget” for your application, from which anyone can derive and create their own gadgets.

The desire:

  • Provide a base gadget that has some sort of standardized chrome and some behavior to be inherited by all derived controls.

The challenge:

  • Regular derived controls won’t be friendly for your users to create controls
  • Regular usercontrols don’t enforce any control template
  • Controls inherit functionality/behavior, but not template. Well, technically you do inherit the style and template, but you can’t really override just a part of the template, you have to modify the whole thing, which would let the users mess around with the chrome you’re trying to keep.

There are a bunch of ways to do that, depending on what part you need to standardize, but one of the more interesting is to create your own UserControl-like class deriving from ContentControl. Other options include allowing other people to make their gadgets using anything and you simply host them in a shim control that has the behavior. In some cases, that’s the better choice, but not in cases where you want them to be able to call methods you provide.

The Base Gadget Control

Our base control is simple, but contained in two parts. The first part is the code (the behavior and model of the control). The second part is the visual representation, contained in its style and template.

Control Behavior

Since we’re not providing any other functionality at this point (you can, but I didn’t want to get into Dependency Properties here), the code has only the static constructor required for styling. The constructor says the default style is the one that targets the Gadget type.

public class Gadget : ContentControl
{
    static Gadget()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Gadget),
                   new FrameworkPropertyMetadata(typeof(Gadget)));
    }

}

All the other behavior is inherited from ContentControl. ContentControl is a specialization of Control which allows for a single element to be inserted as content. In a typical UserControl, this single element is the root Grid.

Control Template and generic.xaml

So from where does the Gadget pick up its style? In WPF and Silverlight, there exists the concept of a generic or default style for a control. That style is contained in the themes\generic.xaml resource dictionary for the library inside which the control exists. The name and location are special.

image

The contents of generic.xaml include styles for one or more controls. The styles contain the control templates which define what the UI of the control is made up of. Since this is a content control, we need to have a ContentPresenter (or another ContentControl) in there, bound to the Content property. Truthfully, you can have anything bound to that property, but if the types don’t match, you’ll get an exception at runtime.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:local="clr-namespace:WpfApplication22"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    
    <Style TargetType="{x:Type local:Gadget}">
        <Setter Property="Padding"
                Value="10" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:Gadget}">

                    <Border BorderBrush="Red"
                            BorderThickness="5"
                            CornerRadius="10">
                        
                        <ContentPresenter Content="{TemplateBinding Content}"
                                          Margin="{TemplateBinding Padding}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        
    </Style>
    
</ResourceDictionary>

The TemplateBinding syntax is what you use to bind to properties of the control that the template is applied to. 

So, our custom gadget simply enforces a red 5px border around all elements. You could also enforce a background, drag handles, close buttons etc.

The Custom UserControls (Gadgets)

Here are the custom UserControls. I simply added a UserControl to the project, and then changed the markup and codebehind to reference Gadget rather than UserControl. To make it friendlier to your users, I’d recommend creating a custom Visual Studio template for your Gadget. The template would set the base class and namespaces automatically.

First Gadget

There’s also a related code-behind, but it’s empty. In a real app, it’ll likely have code. Here’s the Xaml:

<local:Gadget x:Class="WpfApplication22.Gadgets.TestGadget"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:local="clr-namespace:WpfApplication22"
              mc:Ignorable="d"
              d:DesignHeight="300"
              d:DesignWidth="300">
    <Grid>
        <TextBlock Text="My Custom Gadget Content"
                   FontSize="20"
                   TextWrapping="Wrap"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center" />
    </Grid>
</local:Gadget>

 

Second Gadget

Similarly, here’s the second gadget’s markup. This control contains an ellipse.

<local:Gadget x:Class="WpfApplication22.Gadgets.SecondGadget"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:local="clr-namespace:WpfApplication22"
              mc:Ignorable="d"
              Padding="25"
              d:DesignHeight="300"
              d:DesignWidth="300">
    <Grid>
        <Ellipse x:Name="MyEllipse" Fill="Blue"/>
    </Grid>
</local:Gadget>

 

The Main Window

The main Window contains instances of both gadgets. The highlighted areas of the Window xaml are what are needed to load in our own gadgets.

<Window x:Class="WpfApplication22.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:gadgets="clr-namespace:WpfApplication22.Gadgets"
        Title="MainWindow" Height="450" Width="450">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <gadgets:TestGadget Grid.Row="0" Grid.Column="0" />
        <gadgets:SecondGadget Grid.Row="1" Grid.Column="1" />
    </Grid>
</Window>

Here’s how it looks at runtime:

image 

That’s all there is to it for the basics of creating your own usercontrol stand-ins.

If you’re building add-ins or runtime-resolved Gadgets for your own app, take a look at MEF (Managed Extensibility Framework).

WPF Quick Tip: How to Restrict Window Size in WPF 4

Another (paraphrased) question from twitter “How do I set the minimum and maximum sizes for my window in WPF”. The poster wanted to know how to constrain the size of their WPF window to a set minimum height/width and maximum height/width.

I originally replied with a complex answer referring back to my WPF Resize Behavior, because I completely forgot about the simple supported approach:

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350"
        Width="525"
        MinHeight="300"
        MinWidth="500"
        MaxHeight="700"
        MaxWidth="900">
    <Grid>
        
    </Grid>
</Window>

The above markup constrains the size of the window to the sizes indicated by using the MinHeight, MinWidth, MaxHeight and MaxWidth properties. You can also set these from code at runtime.

Use this sparingly. It is generally not a great practice to constrain the size of your application window, or at least not the max size.

Upcoming Deal on my Silverlight 4 Book for Blog Subscribers

If you subscribe to my blog (you’re here, and it’s easy, just do it .. dooo itttt ;) click the RSS link above) there’s a Manning deal on my book coming next week. It’ll only be around for one day (Manning sets the terms, not me) and it is a really good deal.

If you haven’t checked it out yet, I encourage you to do so. Some chapters are already available to people who subscribed to the MEAP (Manning Early Access Program) for the book. That program gets you early on-line versions of chapters as well as updates as I incorporate your feedback. With technology that moves as quickly as Silverlight, it really is a great way to get ahead of the curve.

I have two more chapters (5 and 9) which will be on MEAP soon, and the rest in various stages of completion. Overall, the book is shaping up to be larger than originally anticipated, and certainly larger than the original 371 page Silverlight 2 book. I’ve incorporated lots of community feedback about the previous edition, plus Silverlight feedback in general, added to it a huge dose of what I feel is important and have come up with a really awesome book.

Here’s the current table of contents (subject to change, but not likely to):

  1. Introducing Silverlight
  2. Core XAML
  3. The Application Model and the Plug-In
  4. Integrating with the Browser
  5. Integrating with the Desktop
  6. Sizing, Positioning and Transforming Elements
  7. Displaying Text and Printing
  8. Human Input and Controls
  9. Binding
  10. Validation, Annotation, and Data Controls
  11. Networking and Communications
  12. Dialogs, Navigation, and Partitioning with MEF
  13. The ViewModel Pattern, Testing, and Debugging
  14. Introduction to WCF RIA Services
  15. Graphics and Effects
  16. Displaying and Capturing Images and Media
  17. Animation and Behaviors
  18. Styles, Templates, and Resources
  19. Creating Controls and UserControls
  20. Distribution and Deployment

This book is being targeted to people who want to dive deep into key areas of Silverlight, learn best practices, as well as just plain lean to work with the technology. I’ve made sure it is accessible to good programmers who are new to Silverlight, but not at the expense of making it a book experienced developers will want.

In short, I think this will be the best all-around Silverlight 4 book out there. I know, I’m humble :)

Pete-Brown-Silverlight-in-Action 

So subscribe to my blog (RSS link at the top of this page), and then when the deal shows up next week, be sure to take advantage of it.

Disclaimer: If this sounds like a shameless attempt to get more blog subscribers, it totally is. If it also sounds like a shameless attempt to sell more copies of my book, you’re two for two. Humor me, writing a blog and writing a book are both fun, but a ton of work :)

Getting Started with WPF 4: Button Controls Part 1 – The Button is a Content Control

I have an ongoing twitter search for topics of interest to me and my position at Microsoft, so anything with words like “windows forms”, wpf, windowsclient.net etc. all show up in my search. Thought that, I often find folks who are struggling with how to get started in WPF.

I’ve been meaning to do some beginning WPF tutorials for a bit. Since the main focus of my job is to help people be successful with windows client developer technologies, I figured that would be a good idea. Scott Hanselman once described our job as “starting when you hit File->New Project in Visual Studio”

The latest tweet conversation went like this (latest post at top, starter at the bottom)

image
image

I show this not to single out Christian, but to show one of the roadblocks folks new to WPF often hit: templating of controls.

If you’re used to Windows Forms or even ASP.NET, where purpose-built controls exist for the common scenarios, doing something as simple as creating a flat image button can be somewhat daunting.

The reason is controls in other technologies focus on discrete scenarios, and try to provide properties to handle every scenario they support. WPF (and Silverlight) controls, however focus on the model of the behavior of the control, not the look and feel. The user interface/experience is completely separated from the behavior and implementation.

image

Even looking at the diagram, you can see that the xaml-based approach looks more complex at first glance. However, once you realize that all you need is markup to completely change the user interface for the button (not just borders or shape, but everything about its visual representation) you can see how this approach both scales better and is generally easier to use long-term.

I’m not making a value judgment as to which approach is better, but I personally prefer the template model used by Silverlight and WPF over the purpose-built or partially-templatable, or templatable-with-many-assumptions models used in other technologies. I know many of those technologies have made headway to get away from this model, but they weren’t exactly designed with it in mind.

Each of the button controls in the “Many other Technologies” section could have completely different implementations. They may or may not be based on a common base class, and they may or may not expose similar events or commands. The fact that many do is based more on a convention than something enforced in code. Maybe the events are in a slightly different order, or maybe there is some assumed margin or padding. Maybe you can’t hook certain events like a hover without resorting to Win32 calls, and you almost certainly can’t write a single strongly-typed function that will take in all variants of buttons and do something with them. If you’ve ever spent time getting a complex third-party button to behave just like a customized built-in button, you know what I’m talking about.

In WPF and Silverlight, everything which has normal button behavior derives from the ButtonBase class. The most commonly used derivative of that is the Button class.

image

There are a number of classes in this tree. Looking at them, though, you can see that new classes are created only when new behavior is needed, not when you need a new user interface.

Here is ButtonBase

image

Here is all that Button adds to ButtonBase.

image

To throw in a different one, here’s ToggleButton, the immediate ancestor of CheckBox and RadioButton. Note that it adds new behavior to manage checked and unchecked state.

image

Button is a Content Control

As you can see in the tree above, Button derives from ContentControl. That means Button can contain pretty much anything. We’ll focus on content for most of the rest of this post.

Here’s a Window with a button that contains just some text:

<Window x:Class="WpfApplication19.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>

        <Button x:Name="MyCoolButton"
                Content="Cool Button"
                Width="200"
                Height="75" />

    </Grid>
</Window>

image

So, to create a button which looks like a normal button, but contains an image, how much C#/VB code do we need to write? Answer: None. Button is a content control, so we just assign it an image as the content.

<Button x:Name="MyCoolButton"
        Width="200"
        Height="75">
    <Button.Content>
        <Image Source="Pete-Brown-Silverlight-in-Action.png" />    
    </Button.Content>
</Button>

That’s the long form, spelling out Button.Content. The more common form, since Content is, well, the content property, is to omit that and just nest the content directly in the button declaration. The end result is exactly the same.

<Button x:Name="MyCoolButton"
        Width="200"
        Height="75">
    <Image Source="Pete-Brown-Silverlight-in-Action.png" />
</Button>

image

Similarly, we can assign something more complex, like a grid with an image and multiple rows of text. The content property can have only one element directly contained within it, so compound elements must be contained in something like a grid or StackPanel.

<Button x:Name="MyCoolButton"
        Width="200"
        Height="75">
    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Image Source="Pete-Brown-Silverlight-in-Action.png"
               Margin="5"
               Grid.Column="0" />
        
        <StackPanel Grid.Column="1" Margin="5">
            <TextBlock Text="Buy My Book!" FontWeight="Bold" />
            <TextBlock Text="Pete is writing THE Silverlight 4 book"
                       TextWrapping="Wrap" />
        </StackPanel>
    </Grid>
</Button>

Design-Time in Visual Studio 2010

image

Runtime

image

Content Alignment

If you want to change the alignment of the content, you can use the HorizontalContentAlignment and VerticalContentAlignment properties inherited from ContentControl.

<Button x:Name="MyCoolButton"
        HorizontalContentAlignment="Right"
        Width="200"
        Height="75">

Left
image
Center
image e
Right
image

Left, Center and Right are pretty obvious. There is one more value, Stretch.

Stretch

image

It looks like the Left-aligned version, but if you look closely at the size of the content grid and stackpanel, you can see they now stretch to fill up all available space inside the button, minus the margins.

Similarly, changing the VerticalContentAlignment will, assuming your content isn’t already taking up all available vertical space, affect it just like the horizontal settings.

Content can be Almost Anything, even other Controls

Just about anything can be used as content for a content control, and the button is no exception. In fact, here’s a really crazy assortment of controls included in the button. (Bonus points if you know the song that starts in the listbox – I’m listening to about 20 remixes of it as I type this)

<Button x:Name="MyCoolButton"
        HorizontalContentAlignment="Stretch"
        Width="450"
        Height="155">
    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <Image Source="Pete-Brown-Silverlight-in-Action.png"
               Margin="5"
               Grid.Column="0" />
        
        <StackPanel Grid.Column="1">
            <CheckBox Content="Check if you like turtles"
                      Margin="5" />
            <ListBox Margin="5">
                <ListBox.ItemsSource>
                    <sysCollections:ArrayList>
                        <sys:String>Now how old are you?</sys:String>
                        <sys:String>Where is your harbor?</sys:String>
                        <sys:String>Have many things to do</sys:String>
                    </sysCollections:ArrayList>
                </ListBox.ItemsSource>
            </ListBox>
            
            <Button Content="Open the Door"
                    Margin="5" />
            
            <TextBlock Text="Tell me if the sky is blue" />

        </StackPanel>

        <Image Source="CommodoreLogo_100x100.png"
               Stretch="None"
               Grid.Column="2" />

    </Grid>
</Button>

image

Sure, that’s totally insane for a button, but it can be done. Imagine what it would take to find controls that natively support this type of content in another technology. Heck, finding a button or other control that would allow you to put in two images seems hard to find.

Changing Colors

Of course, you can change the colors of the button without re-templating the control. Simply setting the Background to a color will work:

<Button x:Name="MyCoolButton"
        HorizontalContentAlignment="Stretch"
        Background="Orange"
        Width="450"
        Height="155">
image

You can set it to a gradient if you want a highlight effect similar to the original button. To do that, we break the Background property out using the property element syntax. This allows us to specify a complex property value, a LinearGradientBrush in this instance.

<Button x:Name="MyCoolButton"
        HorizontalContentAlignment="Stretch"
        Width="450"
        Height="155">
    <Button.Background>
        <LinearGradientBrush StartPoint="0,0"
                             EndPoint="0,1">
            <GradientStop Offset="0" Color="#FFAA0000"/>
            <GradientStop Offset="0.49" Color="#FFCC0000"/>
            <GradientStop Offset="0.50" Color="#FF990000" />
            <GradientStop Offset="1" Color="#FF770000" />
        </LinearGradientBrush>
    </Button.Background>

I vant to bite your button!

Ok, so that is one hideous button, but you get the idea. Note that that doesn’t change the hover effect, though. For that, you’ll need to modify the control template, the topic of our next post.

button when we mouse-over

Now what if you want a basic flat button without any re-templating? You can get pretty close by setting colors as well as padding and making sure your button is sized to the image (or is at least using the same aspect ratio.

<Button x:Name="MyCoolButton"
        HorizontalContentAlignment="Stretch"
        Padding="0"
        Background="Transparent"
        BorderBrush="Transparent"
        BorderThickness="0"
        Width="146"
        Height="183">
    <Grid >
        <Image Source="Pete-Brown-Silverlight-in-Action.png" />
        
    </Grid>
</Button>

Button in normal state

Note that you’ll still get the default hover effect, though. Since there is some transparency in my png, I can see a bit of it. The hover border will always show unless you have negative content padding.

Button in mouseover/hover state

And yes, as I mentioned above, changing the padding to a negative size will obscure the border. It’s not the most elegant solution, but it works, assuming your content is not set to a fixed size.

<Button x:Name="MyCoolButton"
        HorizontalContentAlignment="Stretch"
        Padding="-4"
        Background="Transparent"
        BorderBrush="Transparent"
        BorderThickness="0"
        Width="146"
        Height="183">
    <Grid >
        <Image Source="Pete-Brown-Silverlight-in-Action.png" />
        
    </Grid>
</Button>

Be sure to check out Part 2 for information on how to template the button control, including setting the handling for the various visual states.

Silverlight Quick Tip: Controlling the Out-of-Browser Window

If your Silverlight 4 application is running with Elevated Permissions, you can control a fair number of aspects of the hosting out-of-browser window. You can change the size, location, make it top most, set window state and Activate it. Here’s some simple example code:

if (Application.Current.HasElevatedPermissions)
{
    Window win = Application.Current.MainWindow;

    win.WindowState = WindowState.Normal;

    win.TopMost = true;
    win.Height = 200;
    win.Width = 200;

    win.Left = 150;
    win.Top = 150;

    if (!win.IsActive)
        win.Activate();
    
}

Of course, use good judgment when moving the window around, or making it top-most.

Moving a WPF Window with Custom Chrome

Robert Iagar on twitter asked how to move a window in WPF without using the built-in title bar or resorting to user32.dll, so I whipped up this quick sample.

image

So let’s have at it:

Window Xaml

We’ll create a simple window with no built-in border or titlebar. We’ll use a border, some shapes and a HeaderedContentControl to provide stand-in titlebar/content areas.

<Window x:Class="WpfWindowMoveSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle='None'
        AllowsTransparency='True'
        Background='Transparent'
        Title=''
        Height='350'
        Width='525'>
    <Grid>
        <Border Background='Beige'
                BorderBrush='LightBlue'
                BorderThickness='2'
                CornerRadius='10'
                Padding='5'>
            <HeaderedContentControl>
                <!-- New Title Bar -->
                <HeaderedContentControl.Header>
                    
                    <!-- If you want to move using something else, wire up the event there instead -->
                    <Grid MouseDown='OnDragMoveWindow'>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width='*' />
                            <ColumnDefinition Width='Auto' />
                        </Grid.ColumnDefinitions>

                        <Rectangle Grid.ColumnSpan='2'
                                   Fill='LightBlue' />

                        <TextBlock Grid.Column='0'
                                   FontSize='15'
                                   FontWeight='Bold'
                                   VerticalAlignment='Center'
                                   Margin='3'
                                   Text='This is my custom title bar' />
                        <Button x:Name='WindowCloseButton'
                                Grid.Column='1'
                                Width='25'
                                Height='25'
                                Cursor='Hand'
                                Margin='3'
                                VerticalAlignment='Center'
                                Click='WindowCloseButton_Click'
                                Content='X' />
                    </Grid>
                </HeaderedContentControl.Header>
                
                <!-- New Content Area -->
                <HeaderedContentControl.Content>
                    <Grid Margin='3'>
                        <TextBlock Text='Content goes here...' />
                    </Grid>
                </HeaderedContentControl.Content>
            </HeaderedContentControl>
        </Border>
    </Grid>
</Window>

The main line of interest in this window is wiring up the OnDragMoveWindow handler to the MouseDown event of our titlebar grid.

The resulting Window looks like this:

Don't hate me because I'm beautiful

You can’t move it yet, because we haven’t wired up the event handlers. You’ll also have a hard time closing it since we don’t have the close handler wired up.

Code-Behind

Next we need to wire up the event handler to allow for moving the window around.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void WindowCloseButton_Click(object sender, RoutedEventArgs e)
    {
        Close();
    }

    private void OnDragMoveWindow(object sender, MouseButtonEventArgs e)
    {
        DragMove();
    }
}

Note you can also use a command like ApplicationCommands.Close rather than working with an event handler for close. If you’re writing a real application, I suggest you take that route.

That’s all there is to it. If you want to have something else responsible for dragging the window, you simply wire up the DragMove to the MouseDown on that control.

One gotcha has to do with the space the OS normally allocates for the title bar. You’ll notice this if you try and dock the window in Windows 7. The API to address that takes a bit more work, so I’ll address it in a later post.

Back from Best of Tech-Ed/Convergence Reykjavik, Iceland

Last week I had the real pleasure of speaking at the Best of Tech-Ed and Convergence in Reykjavik, Iceland. I was absolutely amazed by the size of the developer and IT community in Iceland, and the turnout at this conference. For an island of about 300,000 people, having a turnout close to 1,200 locals at a conference is pretty amazing.

The participants at the conference were all great folks. Attendees asked both hard and easy questions, and were engaged in the presentations, continuing the discussion into the hallways afterwards. It also helped immensely that just about everyone spoke English fluently as my eight years of French wasn’t going to get me anywhere in Iceland :)

The Microsoft Iceland team was also amazing – they had everything all planned out and treated us as honored guests. The supper on the last night there was an unexpected treat, especially since it turned out two of the waiters were actors playing with us all. :)

Sessions

In addition to wisecracking on the closing panel (hey, no one asked any programming questions :P ), I delivered three regular sessions:

  • Silverlight 4 Deep-Dive: The Commodore 64 Emulator
  • Lighting up on Windows 7 with WPF4
  • Dual Targeting for WPF 4 and Silverlight 4

Closing Panel

It’s great to combine so many of my interests into a group of sessions in one event. I got to talk about Windows 7, sensors, gps location, 8-bit computers (yes, I brought my circa-1982 backup computer), hardcore Silverlight, user experience, and upsizing Silverlight applications to WPF. The turnout in the WPF sessions was excellent, with lots of folks interested in continuing to build cutting-edge desktop and web-connected applications.

Folks who attended the sessions and submitted evals will get the slides and demos from Microsoft Iceland once they complete the evals. Some time after that is all done, I’ll post them online as well.

Cool Apps

While there, I also got to interview folks building some great applications, as well as talk to a local consulting company who is working on moving their Windows Forms application to WPF. I’ve have those interview videos up on Channel 9 soon.

Country

The country itself is absolutely beautiful. I’d love to visit again and dedicate a couple days to taking a good look around and really taking in the glaciers, waterfalls, geysers and all that Iceland has to offer.

image

On the last day there, before the late afternoon flight, Tim Heuer and I took a walk around Reykjavik and checked out the sites and shops. Of course, we both tried out the famous Icelandic hotdog that Clinton made even more famous. We also visited the famous Hofthi house where, among other things, Reagan and Gorbichev met to start the end of the cold war.

image

Tim with hotdog Church of Hallgrímur Leif Ericsson

As you can tell in the photos, it was rainy and cloudy for most of the trip. Amazingly, it was much colder and snowier here at home. Iceland remained around 40F the whole time – shorts weather!

BTW, Coke is everywhere. I’ve never seen so much red and white. Their coke is much better than ours though, using cane sugar and served in glass bottles. I have no idea what the sweetener in Coke Light was, but it tasted much better than Diet Coke. Why do we always send the good stuff overseas?

IcelandAir

The trip back on IcelandAir was bumpy but otherwise uneventful. I was able to get an inexpensive upgrade to the “Comfort” section of the Economy class. That gave me a little extra leg and arm room plus a power outlet, so I was able to get a good part of the next chapter in my Silverlight 4 book written.

Unfortunately, when they did that upgrade, IcelandAir exchanged my connecting UsAir ticket from Boston to Washington, DC for …. nothing. I almost ended up having to spend the evening in Boston, but a last minute runner (literally a runner) came over to the ticket counter in Boston with the exchanged ticket and I made it to the shuttle flight just before the doors were closed. Phew!

IFE

The in-flight entertainment system (a Thales IFE i4500 touch screen) was nice, but the touch screen was absolutely horrible – on both flights, so this wasn’t a fluke. The instructions said you had to hold your finger on the button for “two seconds, and do not press multiple times”. It was pretty finicky at best. It did its job, but the touch screen – the one real interface with the passenger – just stank considering how recently it was installed.

image

I did like the cool map, though.

Overall

I’d definitely go back to Iceland again, especially if invited to speak. The community is great, the hosts were awesome, and the country is beautiful. Highly recommended.

Windows Client Developer Roundup for 2/1/2010

This is Windows Client Developer roundup #9.

I’ve returned from a great time in Iceland. Awesome community and incredible place to visit.

One item of note: If you want to see the WCF RIA Services source code shipped with the product, be sure to vote in this poll.

New blog from the WPF/Silverlight designer team. Check it out.

The Windows Client Developer Roundup aggregates information of interest to Windows Client Developers, including WPF, Surface, Windows 7, XNA, Windows Forms, and some Silverlight. If you have something interesting you’ve done or have run across, please send me the URL and brief description via the contact link on my blog.

WPF

Windows Forms

Cross-Product (WPF, Silverlight, Surface, etc.)

Fun

Windows Client Developer Roundup for 1/25/2010

This is Windows Client Developer roundup #8.

I’m off in Reykjavik Iceland this week, speaking about Silverlight and WPF, but put this together ahead of time to ensure we have some great links for this week.

By now, you’ve probably heard that Visual Studio 2010 and .NET 4’s launch date is April 12, 2010. The teams are doing more performance work to ensure we all have the best possible experience with the tooling and libraries. I, for one, am glad to see the focus on quality over sticking to an arbitrary release schedule.

The Windows Client Developer Roundup aggregates information of interest to Windows Client Developers, including WPF, Surface, Windows 7, XNA, Windows Forms, and some Silverlight. If you have something interesting you’ve done or have run across, please send me the URL and brief description via the contact link on my blog.

WPF

Cross-Product (WPF, Silverlight, Surface etc.)

Windows 7 (and Windows in General)

Surface

Silverlight

Fun Stuff

It’s an awesome time to be a Developer

image

I code for fun.

 

image When I was quite a bit younger, it was pretty early in the era of personal computers, pre-PC revolution. I’ve been pretty clear about how much I loved my Commodore, so I won’t drone on and on about that here (you may breathe a sigh of relief now, but this post reads well with the theme from M.U.L.E. or better yet, a remix of Outrun playing on your headset). Back then, our personal devices – Walkman, early (and crazy expensive) scientific calculators, and…umm.. well crap, there wasn’t much else of interest to carry around other than rubik’s cubes and rabbits foot keychains... anyway, back then, those devices were fixed, you couldn’t really enhance them unless you wanted to start soldering boards.

They were limited by what a small number of designers and engineers thought they should do -- that was the extent of their capabilities.

It’s not like you could write a codec and suddenly your walkman could play DAT cassettes.

Even if you did do some soldering, the possibilities were pretty limited. Later, when I was finishing up high school, programmable scientific calculators that ran a tiny version of BASIC started appearing, but they were limited and (let’s face it) supremely dorky – carrying one around was pretty much an invitation for people either to kick you across the schoolyard, or follow you around like a lost puppy, hoping you’ll cough up the math homework answers before 6th period.

imageIt was easy to get in to programming because for programming, you basically had just computers. You could go super deep on a single platform and form factor. However, the experience was very limited by that fact.

Programming was a sit-down desk-oriented hobby, and if you wanted to show someone what you had done, you either had to hook up ye old 800 pound VCR to the C64 video output (loved that) and bring a tape to show your friends, or drag people over to your computer so they could nod and pretend they understood just how much effort you just expended to make that ball bounce around the screen. Sometimes *gasp* you would just print all the stuff out on beautiful fanfold (crinkled and half-separated on one side from jamming, of course) and show people your printouts. Sometimes you’d upload stuff to a BBS, but there was no always-on internet connection to use to show people what you’ve done, and screenshots weren’t exactly friendly to 300bps modems.

So, it was fun. You programmed for computers, often just for the sake of doing it. The stuff wasn’t portable, so you were forced to stick to the bedroom/den/basement/dungeon or wherever you coded.

image Today though, it’s a different story. It seems like everything and everyone is coming out with APIs and SDKs for their devices. You can code for pretty much all the devices you’d care to. In fact, if you manufacture or run something useful as a device or web site and don’t have an API or SDK, you severely limit your product growth as 3rd party and consumer-written apps are killer (iPhone and Windows are both proof of that).

Virtually every phone we carry can be programmed. Initially you had Java and C++, later .NET and with the iPhone, ObjectiveC (and MonoTouch/.NET). With the Android you can do pretty much whatever you want to the OS, assuming the carrier hasn’t locked you out, and with the upcoming Windows Phone and rumors of Silverlight on same, we can all build some awesome apps. You can write code for something in your pocket, carry it around and make use of it in the supermarket (not to buy brussel sprouts), club, whatever.

image While most of those devices are computers in all but name, we’ve also got netbooks for dirt cheap that are as small as a hardback book, a third as thick, and weigh even less. They’ll run most modern operating systems and let you code on them using just about whatever you want. It’s your whole development studio or design portfolio, and fits in a purse (or, umm, a man purse, I guess, not that I’d know <g>)

Back when I actually had time to play video games on a console, it was all a closed system. There were hacks to create your own trusted cartridges without paying royalties and signing huge contracts with the console vendor, but it was a real chore to find the info and program the chips. Today, if you want to write games to run on your Xbox, all you need is .NET and XNA and membership to a very open creator’s club. It encourages exploration and experimentation, and helps provide a huge audience of people to try out your stuff.

The developer community makes it better.

image We have microcontrollers like the Arduino, robotics like Lego Mindstorms, watches that run micro frameworks, desk phones with full computers embedded in them, smart panels, programmable homes, and now an ebook reader (Kindle) that too has an SDK so you can write your own casual games or whatever else you want to run on it. No one bought the Kindle thinking it was a development platform, but Amazon has decided to make it into one, make it far more useful than just a book reader. It will break out of the world of product designers and engineers and grow in directions perhaps unconsidered by the manufacturer.

Entertainment centers are as programmable as desktop computers (assuming DRM and “trusted paths” don’t get in your face), and today’s equivalent of the walkman (Zune etc.) can run most any code you throw at it. Zune will even let me run my .NET code using the same development environment and libraries as the Xbox.

image The proliferation of developer-friendly devices is a bit like Mozart waking up one morning and finding out that anything can be an excellent musical instrument as long as you tell it the notes to play – no other artists required.

Or perhaps more appropriately, it’s like my kids just found out they can color on any wall they want.

That’s awesome :)

 

The Win7 Sensor and Location API: Introduction to Working with Location in .NET 4 Beta 2

Windows 7 introduced the Sensor and Location API. I’ve previously blogged about the sensor API, but couldn’t wait to get into the Location side of it.

Location API Overview

The location API is a specialized part of the overall sensor API. Many portable devices, laptops and tablets are starting to include GPS and WIFI equipment, both of which can be used to idenfity your current location. Given the ubiquity and interest in it, location was important enough to break out from the rest of the API to enhance usability and discoverability.

image 

(image source MSDN)

There are multiple flavors of location data. First is the default location data set in Windows 7. If you write an application that uses the Location API, and the user has no location devices, and has not previously entered a default location, they will be automatically prompted:

image

image

The default location is the fallback location for sensor-less machines. It also tends to work best on stationary PCs, as you’d have to update the address information otherwise. The second type of information is coordinate (latitude/longitude) information. We’ll cover both after we deal with initializing the device.

Starting a Provider (or Watcher)

To use the location API, you simply create a new GeoLocationProvider (changed in RC/RTW, see note at the end of this post) and hook the appropriate events. The first event of interest is the StatusChanged event. That will tell you if the device is ready, or you lose signal etc.

GeoLocationProvider provider = new GeoLocationProvider();

provider.StatusChanged += (s, ev) =>
    {
        StatusText.Text = ev.Status.ToString();
    };

    // other events here

StatusText.Text = "Waiting for data...";

provider.Start();

To start reporting data, call the Start method.

Once you have the device wired up and ready, you may want to capture the address information.

Civic Address Location

Accessing the address location information is pretty simple. In Beta 2, use the LocationChanged event on the GeoLocationProvider.

provider.LocationChanged += (s, ev) =>
    {
        StringBuilder builder = new StringBuilder();

        builder.AppendFormat("Address1: {0}\n", ev.Location.Address.AddressLine1);
        builder.AppendFormat("Address2: {0}\n", ev.Location.Address.AddressLine2);
        builder.AppendFormat("Building: {0}\n", ev.Location.Address.Building);
        builder.AppendFormat("FloorLevel: {0}\n", ev.Location.Address.FloorLevel);
        builder.AppendFormat("City: {0}\n", ev.Location.Address.City);
        builder.AppendFormat("StateProvince: {0}\n", ev.Location.Address.StateProvince);
        builder.AppendFormat("CountryRegion: {0}\n", ev.Location.Address.CountryRegion);
        builder.AppendFormat("PostalCode: {0}\n", ev.Location.Address.PostalCode);

        LocationText.Text = builder.ToString();

        UpdateDrawing(ev.Location);
    };

On my machine, since I only have the zip code in the default address, that is all that is reported here.

More interesting than address, for this example anyway, is the coordinate location returned from the GPS.

Coordinate Location

Coordinate location (lat/long) is what I was most interested in playing with. It’s important to note, though, that both lat/long and address are part of the same overall location API, and can be used in similar ways in your own applications.

image If you’re looking for a GPS that will work with the API, pick up a copy of Microsoft Streets and Trips 2010 – the one with the black UBlox GPS included. You can then download the Win7 driver for that from http://www.ublox.com/en/usb-drivers/windows-7-driver.html

For my own sample application, that’s what I used. The device reports lat/long and timestamp as you move about. If you use it, I recommend using the extension USB cable (or better yet, get an extension that is both longer and has a firmer grip) in order to minimize interference from the laptop. Some laptops emit enough interference that it makes it next to impossible to get a signal. The reason I recommend a cable with a firmer grip is because the GPS dongle easily pulls out of the extension cord. You could use tape or something to remedy that, but as I mention below, you’ll probably want a longer cable anyway.

image The reason you’ll want a longer cable is to allow you to stick the sensor (assuming this is in your car) up on your dash or window and keep the laptop somewhere like the console or the seat next to you. The little cable that comes with streets & trips is barely long enough for that in my Odyssey.

The other thing you’ll want to do is get some sort of velcro or sticky back to keep the usb dongle up on your dash. The device weighs almost nothing and the USB cable easily drags it down off the dash – especially when you’re flying around the corner, not watching where you’re going because you’re looking down at the screen on your tablet while your son in the back seat is asking what the heck you’re doing with that computer in the car ;)

Anyway…

Getting lat and long is really simple. My main bit of advice for you here is to try and minimize the churn by making sure you’re far enough away from the last reported lat/long to care about it. This is important when plotting points or otherwise working with the data. The GPS reports lat/long so often that unless you’re on the highway going 100mph (again, not that I’d do that, heh) the distance changes can be pretty minute.

Back to the LocationChanged event, plug in this code to get the coordinates, heading and speed (the ublox dongle only reports the coordinates, you can calc heading and speed)

builder.AppendFormat("Latitude: {0}\n", ev.Location.Coordinate.Latitude);
builder.AppendFormat("Longitude: {0}\n", ev.Location.Coordinate.Longitude);
builder.AppendFormat("Heading: {0}\n", ev.Location.Heading);
builder.AppendFormat("Speed: {0}\n", ev.Location.Speed);

So, I put that all together and built a little WPF 4 application that shows your position on a grid. I inverted my Y axis, unfortunately (math kills me every time), but otherwise it worked great. I call it “GPS Etch-a-Sketch”

image

I put the Dell XT2 tablet in the Odyssey and drove my son to his gym class at Rolly Pollies. On the way back, I captured the activity in Camtasia, and also snagged this screenshot. On this machine, I have no default location information (not even a zip code) but was not prompted for any since I did have a location reporting device attached.

The red half-moon in the middle of the track is a rendering artifact. I think it’s the video driver in this Dell, or it could be a result of running this with Camtasia on.

Here’s the video (available starting around 2:30pm 1/23/2010), sped up to 800% so you didn’t have to live through 20 minutes of driving, including all the stop lights and the Arby’s drive through (with the speed-up, I couldn’t resist sticking the Benny Hill music in there <g>)

Here’s the code I used for plotting the points (lines, actually) on the window

private void UpdateDrawing(GeoLocation location)
{
    if (!double.IsNaN(location.Coordinate.Latitude) && !double.IsNaN(location.Coordinate.Longitude))
    {
        if (!_firstReading)
        {
            // plot a line from last point to this one.
            Point plotPoint = TranslateLatLongToScreenPoint(location.Coordinate.Latitude, location.Coordinate.Longitude);


            // avoid plotting the same 1pt lines over and over
            if ((int)Math.Round(plotPoint.X) != (int)Math.Round(_previousPoint.X) &&
                (int)Math.Round(plotPoint.Y) != (int)Math.Round(_previousPoint.Y))
            {
                Line line = new Line();

                line.X1 = _previousPoint.X;
                line.Y1 = _previousPoint.Y;
                line.X2 = plotPoint.X;
                line.Y2 = plotPoint.Y;

                // TODO: vary thickness or color by speed. If not varying, can use a polyline instead
                line.StrokeThickness = 3;
                line.Stroke = Brushes.Green;

                // add the line to the plot area
                PlotArea.Children.Add(line);

                // setup for next line
                _previousPoint = plotPoint;

            }

            // move the turtle and set its heading (TODO)
            Canvas.SetLeft(Turtle, plotPoint.X - Turtle.ActualWidth / 2);
            Canvas.SetTop(Turtle, plotPoint.Y - Turtle.ActualHeight / 2);

        }
        else
        {
            _firstReading = false;

            _startingLatitude = location.Coordinate.Latitude;
            _startingLongitude = location.Coordinate.Longitude;

            // calculate top left corner of plot area by figuring out the center
            _plotAreaTopLeftLatitude = _startingLatitude - ((PlotArea.ActualHeight / 2.0) / PixelsPerDegreeLatitude);
            _plotAreaTopLeftLongitude = _startingLongitude - ((PlotArea.ActualWidth / 2.0) / PixelsPerDegreeLongitude);

            // calculating the prev point after calculating top left will effectively center the plotting
            _previousPoint = TranslateLatLongToScreenPoint(location.Coordinate.Latitude, location.Coordinate.Longitude);

#if DEBUG
            // if algorithm worked, this will be 0,0
            Point debugPoint = TranslateLatLongToScreenPoint(_plotAreaTopLeftLatitude, _plotAreaTopLeftLongitude);
            System.Diagnostics.Debug.WriteLine("Top x={0}, y={1}", debugPoint.X, debugPoint.Y);
#endif

            DrawBackgroundGrid(_previousPoint);
        }


        // store new coordinates as last old coordinates
        _previousLatitude = location.Coordinate.Latitude;
        _previousLongitude = location.Coordinate.Longitude;

    }

You can see that on the first reading from the GPS, I identify the center of the drawing (the start point) and draw the grid. I also set up the lat/long of the top-left based on all that.

My TranslateLatLongToScreenPoint function is messed up on the Y axis, so I’ll refrain from posting the code here.

Finally, here’s the Xaml. Rather than monkey around with z-order, I just created three different canvasses for me to draw on: the background (grid lines), plot area (the green dots/lines) and the overlay (the red circle). Also, to keep the background lines sharp, I turned on SnapsToDevicePixels.

<Window x:Class="LocationDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowState="Maximized"
        SnapsToDevicePixels="True"
        Title="GPS Etch a Sketch"
        Height="700"
        Width="1200">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="275" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        
        <StackPanel Grid.Column="0" Margin="5">
            <TextBlock x:Name="StatusText"
                       FontSize="14" />
            <TextBlock x:Name="LocationText"
                       FontSize="14"
                       TextWrapping="Wrap"/>    
        </StackPanel>

        <Canvas x:Name="BackgroundArea"
                Background="White"
                Grid.Column="1">
        </Canvas>
        
        <Canvas x:Name="PlotArea"
              Background="Transparent"
              Grid.Column="1">
        </Canvas>
        
        <Canvas x:Name="OverlayArea"
                Background="Transparent"
                Grid.Column="1">

            <Ellipse x:Name="Turtle"
                     Width="15"
                     Height="15"
                     Fill="Red"
                     Opacity="0.75" />

        </Canvas>
    </Grid>
</Window>

Important RC / RTW Changes

Note that the information here applies to Beta 2. Gavin Gear blogged about upcoming changes in the rc and release of .NET 4. Here are two diagrams from his blog.

Current (Beta 2):

image

Planned (RC/RTW):

image

Those changes make a lot of sense since the Address information, reported in every update event, doesn’t change like the coordinate information does.

I’ll update this application (fix some bugs and otherwise clean it up) and post it as a sample after RTW. I don’t want to put a real sample out there using the Beta 2 API.

Applications and Other Things I’ve Written Professionally over the Years

Prior to joining Microsoft, I worked at a consulting company for a bit over 13 years. Prior to that, I started the IT department at a medical billing company and worked there for 4 years while completing my Computer Science degree.

Seeing Scott’s post on past work he did years ago at SparkFun and 800.com got me to thinking about some of the interesting projects I’ve been on. I’ve been a developer, a designer, an architect, a project manager, an engagement manager covering multiple projects, and an analyst. I was happiest, though, when I could get my hands on the code and visual design :)

One thing that was interesting about consulting vs being in internal IT, is your problem domain changed every two to nine months. I met new clients, had to solve new problems and understand a new business on a pretty regular basis. Often times, I’d be on multiple projects at the same time, so it was even more of a stretch.

So here are some interesting ones, in roughly chronological order. No, this isn’t a resume, just some interesting cherry-picked stuff :)

Before I joined Microsoft, I worked for AIS, and before that, I worked for a medical billing company in Massachusetts, so we’ll start there.

Doctor’s Office Billing System – C++

My first application I wrote professionally was a Borland C++ 3 (DOS) medical billing program. I bought a book on how to write a database using C++ – it was all about b-trees and interesting data structures, and wrote the whole thing. It worked reasonably well, had a good dos-based character mode windowing library, and was a decent performer. That was a crapload of custom database code, but I didn’t know any better.

Doctor’s Office Billing System – dBase IV and FoxPro 2.x

Once I realized I didn’t have to write databases from scratch, I used dBase to write the next office billing program. When I moved it to foxpro and added sql statements into the mix, the performance went through the roof. To this day, this is still the fastest database application I’ve written. It was blazing, and the UI was awesome. 

Medicaid Billing Program – VB3/VB4

When I started programming in Windows, I tried Delphi 1.0, PowerBuilder 3, Gupta SQL Windows, Borland C++ with OWL, and Visual Basic 3. The company I worked for at the time felt programmers should buy their own tools just like carpenters so that was a fair outlay of cash to get started, all while still in college. I liked learning all the different tools, though.

While I still have, in production, a Delphi 1.0 app (just found out about that the other day – amazing!), I was most proud of a VB3 app I wrote for UB92 Medicaid billing. It was one great big data entry app with an access database, and an exporter that wrote out Medicaid flat files for writing on a big old tape for submission.

Cruise Ship Group Reservations System – VB4 + COBOL

My first project when I joined AIS was to travel to Miami every Monday and fly back home to Maryland every Friday during the months of June through October. If you’ve ever been to Miami at that time of year, especially if you were a pasty white yankee fresh out of New England like me, you know that’s a rough commute.

The project was interesting. I did UI work in VB4 for the group reservations system for a cruise line. The application connected to a Unisys mainframe and used “stored procedures” written in COBOL. All in all, pretty neat, and my first taste of large-scale application development.

Course Materials / Demos for Intro to VB in French

During December 1996 I traveled to Lille, France for two weeks to teach Visual Basic to a bunch of COBOL programmers. Before I left, I was told I was going there to write some demos. It wasn’t until I arrived that I was told I was to teach a class on VB, in French. My French picked back up in the second week (takes me a week to get immersed) and it went pretty well.

Law Enforcement Evidence Management System – VB4/5 + ASP.NET

Another project in Florida. I’m not sure why I kept getting assigned to Florida-based projects, but hey. This one was pretty neat: a complete evidence management system for the Florida Department of Law Enforcement. The strange thing was the customer had a legislative mandate that it had to be a “web app” – no questions allowed. However, they wanted to do a bunch of desktop integration (automate Word and Excel) as well as have a rapid data entry experience, and integration with a hand held barcode scanner.

This was around the time ASP was first released, and browser apps just weren’t up to the task. What we ended up doing was bundling all the client-side code into activeX controls, and surfacing them through the browser. The users decided they didn’t like the browser chrome, so we had to host a browser control in a VB shell, and then do some hackery to wire up the shell menu system into the browser control and into the activeX controls. Major mess just to meet a misguided mandate.

In the end, due to changing requirements and team attrition, I wrote almost all of the VB code for this application.

Pension Management System – VB6

One of the largest VB applications I ever worked on was a pension management system that used VB6 and (I believe) MTS. Could have been COM+ but I think it was MTS. Back end database was a unisys mainframe using COBOL “stored procedures”

The interesting mandate in this app was I had to write a VB6 framework that would allow client non-programmers who wanted to be programmers (ack!!) to enter in the transaction details, business rules etc. without getting too deep into the architecture.

The solution ended up being a ton of code generation via a custom code generator I wrote for Rational Rose, a custom dataset replacement that had a lot more built-in functionality, and templates that basically had “insert code for X here”. It was successful in the end, but surely would have taken a lot less time to build if not for the desire to allow non-programmers to participate in programming.

.NET 1.0 alpha/beta 2 Day Seminar

Another education task. I gave something like 10-15 of these around the country. In the .NET 1.0 alpha days (when everything was still changing) I did a 2 day seminar using Microsoft-provided decks and demos (which you had to keep modifying to keep up with the bits) showcasing all the major features in .NET. It was all about showing VB6 programmers how cool .NET is, and doing the same for classic ASP programmers. Lots of demos of brand new and exciting technology.

Healthcare Vaccine Clinic Scheduling App – ASP.NET

For this ASP.NET application, I did overall UI design, use-cases and modeling work. I didn’t do much code, and that was a first. This was also the first project where I ended up taking on formal managerial duties.

Stock Trading Regulation Enforcement Reporting Application – ASP.NET and XSLT

Back when it was still called NASD, I wrote an ASP.NET application that was used to show data from a bunch of different systems in a common format. It had to be written so that other systems could be added without requiring changes to source code in the application. I ended up doing a bunch with config files and fairly large custom XSL transforms to allow plugging in various different data sources and get meaningful data from them. The client wrote the (convoluted and huge) SQL statements but otherwise this was a fun little one-man project for me.

Education Bookstore eCommerce Site – ASP.NET 2

Sometimes we got called in to clean up other people’s messes. This was one of those times.

This company had an architect working on an ASP.NET application for a year and a half, unchecked, with no oversight. A month before they had to go live they finally decided to see where the application was. The architect had finished about 3/4 of a completely custom framework that tossed out almost everything in ASP.NET and replaced it with his own patterns. The framework, though, met exactly 0% of the business requirements, as there was no app to show.

On this I led a team and also did a ton of ASP.NET coding. We tossed out the custom framework, went straight to in-box functionality – working 15 and 20 hour days, and a number of 24 hour days, and got the online bookstore up and running just in time to meet the summer demand period. You see, they existed as the online bookstore for schools and universities, and if they weren’t live in early summer, they were out of business. We cut this so close that we were taking orders on the site before the credit card charging part of the application was completed. It took about a week before the CC charging bits were done and cards were actually run and charged.

This turned out to be a fairly ungrateful client in the end, but I was really happy with what we accomplished here. I can truthfully say that my team saved this company from going out of business, and that’s a feel-good thing for sure :)

Auto Glass Claims Counselor App – .NET 2 Windows Forms + COBOL

Around the early .NET 2 timeframe, I worked on a Windows Forms project for a large insurance company who happens to have a green mascot. I did mostly the UI and a little back-end on this.

This was the project I always tell people about where the client wanted a UI that looked cool and modern, but couldn’t get capital budget for 3rd party controls. They decided there was less friction in having me do a ton of custom painting for windows forms controls since that was coming out of a staffing budget and didn’t require such a big approval process.

Mobile Phone Store – ASP, ASP.NET, C#, .NET 1.1 and 2

One of my almost purely management projects (I had 11 team members) was for an online Mobile Phone Store for a major electronics retailer, though a company that did all the actual selling and fulfillment for the phones. The platform the team had to build on was set, we “just” had to augment it with a bunch of new functionality, new skins etc. The platform was an interesting combination of ASP.NET that then called a checkout process in classic ASP, and then bounced back to ASP.NET. Oh, and the ASP.NET code was in the process of being converted from 1.1 to 2.0, so that was extra fun :)

The project was a success and the customer and the electronics retailer were both very happy with the results and the process. While this customer went through a bankruptcy process much later and have a different name now, they were always good folks to work with.

For this same customer, I ended up doing some Amazon.com integration work later. That was my first exposure to the hot mess that is the amazon catalog and partner system. I only hope it has gotten better since then.

Carbon Calculator – Silverlight 1.1 Alpha

My first foray into RIA was with Silverlight 1.1 alpha. I and a colleague built the Carbon Calculator for Conservation International. While the app was functional, it was ugly, and this was my first experience with hitting the limitations of my own design abilities and deciding future projects would need a real designer.

You can see some info and screenshots of the calculator here.

I’m happy to say, though, that this project cemented my interest in Silverlight. Also, due to the permission I got to deploy the app into production, it also let me say we had the first and only Silverlight managed-code application in production at the time. I’ve always taken pride in that.

MSDN East Coast News – Silverlight 2

MSDN East Coast News  is a Silverlight 2 app that I built (through AIS) at the request of some of our local DPE folks. I had some availability, and was the only person willing to put in a bunch of my own time, so I did this one solo.

This was the first time I did any Facebook integration. Of course, it was also done at the time Facebook was changing their API and the application screen layout. What a mess that was.

I’m pretty proud of the app I designed and built here. It worked well and did most of what we envisioned. This is also the app I used to develop some of the early patterns I used in other Silverlight applications. You can find more information on it here.

Document Search Application – Silverlight 3 in SharePoint

One of the last applications I worked on at AIS was a SharePoint document search application. The customer wanted Silverlight for the rich UI, but more importantly, for speed and document/index caching. This customer has field reps who are often on the other end of a very slow dial-up connection, so they needed to pre-seed their laptops with index data, and have a good way to incrementally update that to allow document searches that were much quicker than the all sharepoint approach. They also wanted to experiment with other ways of visually classifying the data and otherwise augmenting the search.

On this project, I worked with the customers design team for the UI. I did all the initial UX work (with them in the room) using SketchFlow pre-release bits on my laptop, and then walked them through wireframes and a progressively higher fidelity prototype. The visual design team then took the screens we all came up with, and made them look SOO much better. They were involved from day 1, so they knew the UX, and the types of constraints we had to work within. It was a good experience all around.

I wasn’t there for the completion of this project, but I left it in very good hands.

 

Of course, in 17+ years of work there are quite a few other applications and projects I left out (not counting all the things I did on my own), but those are the ones that always stand out in my mind. Since I don’t actually write applications for a living any more <g>, I figured I’d put this list in web-cement for future generations of computer nerds to marvel at :)

More Posts Next page »