Andrej Tozon's blog

In the Attic


Developing for ASP.NET mobile

Visual Studio 2008 introduced a lot of new features to support new technologies, adding some cool new designers to developer’s tool belt. On the other hand, support for some technologies was simply left out, leaving a some developers very unhappy. One of those was support for SQL Server 2005 BI projects (including 2005 Reporting Services).

A (long) year after its release, I learned that there was another feature dropped in VS2008 – support for designing ASP.NET mobile web forms. This doesn’t mean you can’t develop, compile and publish ASP.NET mobile forms; it simply means they pulled out the designer and mobile forms item templates out of Visual Studio 2008. Getting item templates back is the easy part, you can get them here. For the design view support, I’m not currently aware of any plans to put it back in the future.  But really – with mobile browsers getting more powerful each day, capable of rendering rich(er) (x)html, do we still need the simplicity and extendibility of ASP.NET mobile forms? For the time being, the answer may still be yes, if you’re planning to support a wide range of mobile devices. Whatever the future, the current (un)support for ASP.NET mobile in Visual Studio works for me. It’s true that I’m unable to design mobile forms in design view, but I do that rarely even with their bigger brother - ASP.NET web forms.

ASP.NET? Mobile?

Strangely enough, I’m doing more web than client development lately. Go figure.

Speaking of webby/clienty things… Silverlight 2.0 RC0 was just made available. Downloads include Microsoft Silverlight Tools for Visual Studio 2008 SP1 and Microsoft Expression Blend 2 Service Pack 1 Preview. Note that Microsoft Expression Blend 2 SP1 is a replacement for Expression 2.5, which is no more.

Creating splash screens with Expression Designer

Did you know you can create cool looking splash screens for your WPF application right there with the Expression Designer?

Of course you did. Expression Designer provides you with all you need to create free-shaped, part-transparent, drop-shadowed graphics and I bet the the WPF splash screen support is going to be baked into the next release of Expression Blend as well.

This is a quick walk through designing a splash screen with the Expression Designer.

1. With Expression Designer open, create a new rectangle and set its Corner Radius property to about 30px (depending your rectangle’s size).

2. Set rectangle’s color to match your application theme and make it a bit transparent by setting Opacity to around 70%.


3. Find the Effects property section and click the Add Effect button. Choose Effects | Drop Shadow.

Add Effect

4. Decrease Softness and Offset and increase Opacity properties to make the shadow more compact. You will end up with something like this:

Drop Shadow and Transparence

5. Create a new layer and put a new rectangle on it. Make it the same size as the first one and put it on the same spot to make them both aligned exactly.

6. Set its stroke to None and fill it with a transparent gradient: First Stop Alpha: 80%, Second Stop Alpha: 0%.

7. Move gradient’s origin more to the side and make it larger.


Your rectangle should now look just a little bit more exciting:

Light source

8. Time for some text… With the Text tool, create your application title. I’ve chosen 36 pt Arial Rounded MT Bold font with white color fill. Applying some transparency to the text will make it absorb some background color for a more glassy look. You could add some Outer Glow Effect to make it even cooler.

9. Add all other text you want to show in your splash screen. Here’s what I got so far:

Title & Text

10. If you have any graphics that could communicate to the user what your application is all about, you could use that as well. It might also be a screenshot from the actual application if you can’t find anything better. I used a screenshot of my sample Live Europe Weather Map application. Adding a bitmap to the existing Expression Design project is really easy – just select File | Import… and open your graphics - it will get added to the current layer so you will probably want to create a new layer before doing that. And don’t forget to set some transparency to that as well:


11. Almost done. To break out of dull symmetric rectangly shape, you can mix in some additional decorations, like I did to point out that this is a whole new version of the application [the yellow badge is from the bittbox badges collection:

 Final Splash

And this is the final result for now. We’ve got transparency, irregular shape, drop shadow… Of course, this works for a sample, but for a real-world application I would have to put some additional work into it; pay more attention to the details, colors, gradients, etc.

12. When satisfied with your work, just select all objects, select File | Export… and choose PNG as your target format. After the file is saved on your disk, all you need is incorporate it in your WPF application.

Expression Design offers a lot more effects and options that were shown in this quick walkthrough. I am particularly happy to see how easy it is to play with different effects, mixing and layering them in different combination. There is, of course, also export to different Xaml instances, which makes it even more sweet.

While writing this post, I noticed that the WPF team published a new WPF Splash Screen Item Templates for Visual Studio 2008 SP1. This gives you additional option to add a splash screen to your WPF application – a new (Splash Screen (WPF)) item will be available in your templates window when adding a new item. Selecting that will insert a default graphics to your project and set it as the splash screen. You’ll have to customize the graphics yourself though. This is a nice option, although I’d like to see some form of a wizard with some styling options, font/title selections, etc… In the next version of Visual Studio perhaps…

Live Europe Weather Map in action

As promised, here’s my Live Europe Weather Map in action. This is still just a basic example of displaying icon pushpins on a map, and because I’m using Virtual Earth ASP.NET Map Control, I don’t need to worry about how map is handled and pushpins are displayed, I only need to provide data for the pushpins.

Live Europe Weather Map 

The first version of the Weather Map from a couple of years ago used to scrape the data off a Html Page. Recently, the National Environmental Agency started publishing weather data in a more collection-friendly data formats, so I switched to these.

The current version of Live European Weather Map collects Xml files, containing weather observations for European Capitals and additional cities.

Data Collection

I decided to go with LINQ to SQL option for shaping my data entity. Some may argue that LINQ to SQL isn’t a serious technology, but for small, compact projects like this, it gives me just what I need:

1. Instead of generating my data classes manually, I can create a table in my database (SQL Express in this case) and pull my classes out of that.

2. I can create my data entity by drag and dropping a table from the data source to the LINQ to SQL Class Designer in Visual Studio 2008, and my data class would get generated automatically. Here's what I’m currently collecting for weather conditions:


3. I can use this class to collect the data and store in into the database, or I can simply just store the collected data into ASP.NET Cache and forget the database completely.

Of course, I could’ve done it some other way (plenty of options), but this one seemed the easiest and quickest.

Weather data collection is done in a background, with a HttpModule and a timer, set to fire the collection process every 60 minutes (configurable through web.config):

   1: public void Init(HttpApplication application)
   2: {
   3:     int interval = GetCollectIntervalSetting();
   5:     if (timer == null &&  interval > 0)
   6:     {
   7:         timer = new Timer(new TimerCallback(BackgroundCollectionCallback), application.Context, 0, interval);
   8:     }
   9: }
  11: private void BackgroundCollectionCallback(object sender)
  12: {
  13:     WeatherCollector.UpdateConditions();
  14: }

Using LINQ to SQL, collected data is inserted into the database:

   1: public static void UpdateConditions()
   2: {
   3:     List<WeatherCondition> items = Collect();
   5:     WeatherDataContext context = new WeatherDataContext();
   6:     context.ExecuteCommand("delete dbo.WeatherCondition");
   7:     context.WeatherConditions.InsertAllOnSubmit(items);
   8:     context.SubmitChanges();
   9: }

… and later read from it:

   1: public static WeatherCondition[] Read()
   2: {
   3:     WeatherDataContext context = new WeatherDataContext();
   4:     var conditions = from item in context.WeatherConditions
   5:                      select item;
   6:     return conditions.ToArray();
   7: }

… just to finally get shown on the map:

   1: protected void Page_Load(object sender, EventArgs e)
   2: {
   3:     if (IsPostBack)
   4:     {
   5:         return;
   6:     }
   8:     AddWeatherPins();
   9: }
  11: private void AddWeatherPins()
  12: {
  13:     WeatherCondition[] conditions = WeatherCollector.Read();
  15:     for (int i = 0; i < conditions.Length; i++)
  16:     {
  17:         WeatherCondition condition = conditions[i];
  18:         if (condition.ConditionIcon == null || condition.ConditionIcon.Length == 0)
  19:         {
  20:             continue;
  21:         }
  23:         AddPin(condition);
  24:     };
  25: }
  27: private void AddPin(WeatherCondition condition)
  28: {
  29:     StringBuilder sb = new StringBuilder();
  30:     sb.AppendFormat("<p><b>{0} {1}</b>, {2}", condition.Temperature, condition.TemperatureUnit, condition.Condition);
  31:     if (condition.Weather.Length > 0)
  32:     {
  33:         sb.AppendFormat(", {0}", condition.Weather);
  34:     }
  35:     sb.Append("<br />");
  36:     if (condition.WindStrength.HasValue)
  37:     {
  38:         sb.AppendFormat("Wind: {0}, {1} {2}<br />", condition.WindDirection, condition.WindStrength, condition.WindStrengthUnit);
  39:     }
  40:     if (condition.Humidity.HasValue)
  41:     {
  42:         sb.AppendFormat("Humidity: {0} {1}<br />", condition.Humidity, condition.HumidityUnit);
  43:     }
  44:     if (condition.Visibility.HasValue)
  45:     {
  46:         sb.AppendFormat("Visibility: {0} {1}<br />", condition.Visibility, condition.VisibilityUnit);
  47:     }
  48:     if (condition.Pressure.HasValue)
  49:     {
  50:         sb.AppendFormat("Pressure: {0} {1} {2}<br />", condition.Pressure, condition.PressureUnit, condition.PressureText);
  51:     }
  52:     sb.AppendFormat("<br />Updated: {0}</p>", condition.UpdatedTime);
  54:     Shape pin = new Shape(ShapeType.Pushpin, new LatLongWithAltitude((double)condition.Latitude, (double)condition.Longitude));
  55:     pin.Title = string.Format("{0}, {1}", condition.City, condition.CountryCode);
  56:     pin.CustomIcon = string.Format("images/{0}.png", condition.ConditionIcon);
  57:     pin.Description = sb.ToString();
  58:     map.AddShape(pin);
  59: }

Note that a large portion of the code is spent for describing pushpin’s popup content.

Again, this is just a drag’n’dropped Virtual Earth Map Control put to work here, without any specific client or server-side events. Looking forward to explore those in the future.


While next release of WPF (3.5 SP1) won't yet align with Silverlight's "Parts & States Model"  by not introducing VisualStateManager into its API, it's good to know that VSM is definitely coming to WPF. Even more, John Gossman has just released a prototype of his VisualStateManager for desktop WPF, which is compatible with Silverlight Beta 2 VSM implementation.

Before VSM is built into the core of WPF, this prototype lets us explore and play with this "new way" of controls' state transitioning in WPF applications. Sweet.

The tide is high – new MS downloads

SQL Server 2008 RTM is out!

Microsoft Sync Framework v1.0 RTM is out!

  • Sync Services [now @ v2] is “synchronized” with Sync Framework
  • Peer 2 peer database sync support
  • Sync with device’s Database
  • SQL2008 Change Tracking supported
  • Sync process tracing

A couple of features of the above products require VS2008/.NET 3.5 SP1, which means VS2008 / .NET 3.5 service pack duo should be released real soon now [by August 11th, as stated on MSDN).

Like it’s not hot enough already… turning my air-con down to keep my boxes cool and running…

[Update] SQL Server Compact 3.5 SP1 is out!

[Update] .NET FX 3.5 SP1 is out!

  • ADO.NET Data Services
  • Entity Framework
  • ASP.NET Dynamic data

[Update] Visual Studio 2008 SP1 is out!
[Update] Need to update Silverlight Tools for VS2008 too.

Sources: here, here, here, here

Live Europe Weather Map with Windows Live Tools Map Control

A while ago I built a sample weather map using Atlas [now Microsoft Ajax] and VirtualEarthMap control, which used real-time data to display current weather conditions.

VirtualEarthMap control was steadily progressing all this time as a part of a separate SDK, until released as a new ASP.NET control with the latest Windows Live Tools for Microsoft Visual Studio release last week [July CTP, download here].

Working with the control appears to be easy. It took me about 15 minutes [including Tools’ download+setup] to port the previous version to use this new control. No RTFM, just drag and drop, set properties and copy/modify some relevant code. And still, the current implementation consumes only small part of functionality this control offers, leaving a lot of space for additional enhancements.

Here’s a screenshot of the control in action:

Europe Weather

What the application does is capture the weather data from the national Environmental Agency and display them on the map as custom pushpins, each pushpin representing a city, where the readings are being collected; hovering over each pushpin will give you more information about that city weather station’s readings.

I’m going to post a live example with some code after I give this control some more time to show me what it can really do.

Label.Target Pt.2: The return of the (not so) attached property

Following my previous example, this is another experiment with the Label.Target property.

Suppose you want to restrict user’s progression with data input on a form by disabling some crucial input fields, which input depends on some other fields on the form. There’s more than a couple of ways for doing this and the first solution that springs to mind would be doing it by employing business object data validation. But if you need a pure UI/XAML solution, this can be the alternative:

[See it live – loose Xaml page ahead ]

What’s happening in the sample above – the second TextBox gets enabled only when the first TextBox is not empty. The same goes for the third box, except here’s the second box that has to have some text entered into it.

This was done with the help of data triggers:

   1: <Label Target="{Binding ElementName=firstBox}" Content="_1st:" />
   2: <TextBox Name="firstBox" Grid.Column="1" Margin="2" /> 
   3: <Label Target="{Binding ElementName=secondBox}" Content="_2nd:" Grid.Row="1" />
   4: <TextBox Name="secondBox" Grid.Column="1" Margin="2" Grid.Row="1">
   5:   <TextBox.Style>
   6:     <Style TargetType="{x:Type TextBox}">
   7:       <Style.Triggers>
   8:         <DataTrigger Binding="{Binding Path=Text.Length, ElementName=firstBox}" Value="0">
   9:           <Setter Property="IsEnabled" Value="false" />
  10:         </DataTrigger>
  11:       </Style.Triggers>
  12:     </Style>
  13:   </TextBox.Style>
  14: </TextBox>
  15: <Label Target="{Binding ElementName=thirdBox}" Content="3rd:" Grid.Row="2" />
  16: <TextBox Name="thirdBox" Grid.Column="1" Margin="2" Grid.Row="2"> 
  17:   <TextBox.Style>
  18:     <Style TargetType="{x:Type TextBox}">
  19:       <Style.Triggers>
  20:         <DataTrigger Binding="{Binding Path=Text.Length, ElementName=secondBox}" Value="0">
  21:           <Setter Property="IsEnabled" Value="false" />
  22:         </DataTrigger>
  23:       </Style.Triggers>
  24:     </Style>
  25:   </TextBox.Style>
  26: </TextBox>

There’s a lot of repetitive Xaml code above that can be put away by using a style and an attached property.

[Note: I’m going to hijack the Label.Target dependency property here just because it suits the needs for this sample - it’s not even registered as an attached property and this wouldn’t even compile in Visual Studio! In a real application you would want to produce a completely new attached property to avoid all potential troubles that may result from such (mis)use]

As mentioned in the previous post, a Label.Target property can hold a reference to another control on the page. We’re going to use the property to point to the dependency source control:

   1: <Label Target="{Binding ElementName=firstBox}" Content="_1st:" />
   2: <TextBox Name="firstBox" Grid.Column="1" Margin="2" /> 
   3: <Label Target="{Binding ElementName=secondBox}" Content="_2nd:" Grid.Row="1" />
   4: <TextBox Name="secondBox" Grid.Column="1" Margin="2" Grid.Row="1"
   5:   Label.Target="{Binding ElementName=firstBox}" />
   6: <Label Target="{Binding ElementName=thirdBox}" Content="3rd:" Grid.Row="2" />
   7: <TextBox Name="thirdBox" Grid.Column="1" Margin="2" Grid.Row="2" 
   8:   Label.Target="{Binding ElementName=secondBox}" />

The global style is applies the same principle, shown in the previous post:

   1: <Style TargetType="{x:Type TextBox}">
   2:   <Style.Triggers>
   3:     <DataTrigger Binding="{Binding Path=(Label.Target).Text.Length, RelativeSource={RelativeSource Self}}" Value="0">
   4:       <Setter Property="IsEnabled" Value="false" />
   5:     </DataTrigger>
   6:   </Style.Triggers>
   7: </Style>

The data trigger in the above style disables the target TextBox when its Length property is set to 0.

This looks good already, but something is not right… Hint: try the current example live and fill all three boxes, then clear the first one.

We need to fix this and we’ll do it by adding another data trigger, which disables the current TextBox whenever the source TextBox is disabled. Here’s slightly modified version of the style:

   1: <Style TargetType="{x:Type TextBox}">
   2:   <Style.Triggers>
   3:     <DataTrigger Binding="{Binding Path=(Label.Target).Text.Length, RelativeSource={RelativeSource Self}}" Value="0">
   4:       <Setter Property="IsEnabled" Value="false" />
   5:     </DataTrigger>
   6:     <DataTrigger Binding="{Binding Path=(Label.Target).IsEnabled, RelativeSource={RelativeSource Self}}" Value="false">
   7:       <Setter Property="IsEnabled" Value="false" />
   8:     </DataTrigger>
   9:   </Style.Triggers>
  10: </Style>
Well, that’s all, really… A simple example to show the power of WPF data binding through the attached properties. [A post on creating a proper attached property for this sample will follow as I move away from Xaml-only examples]

And this is the final result code for this post [See it in action – loose Xaml file]

Label.TargetProperty as a Source

One of probably most underused features in windows desktop UI development world is got to be the use of a Label as an accessor to its pair control. I rarely see developers using this possibility to enhance keyboard UI navigation.

A couple of things changed about this mechanism when going from Windows Forms to WPF:

  1. The escape character to mark the mnemonic (the letter/key for accessing related control) changed from ‘&’ to ‘_’;
  2. In Windows Forms, the control that received focus was always the one that was next in tab order. With WPF, the pair control is specified with the Label.Target dependency property.

A simple form with this feature enabled would look like:

   1: <Grid>
   2:   ...
   3:   <Label Target="{Binding ElementName=firstNameBox}" Content="_First name:"/>
   4:   <TextBox Name="firstNameBox" Grid.Column="1"/> 
   5:   <Label Target="{Binding ElementName=lastNameBox}" Content="_Last name:" Grid.Row="1" />
   6:   <TextBox Name="lastNameBox" Grid.Column="1" Grid.Row="1"/> 
   7:   ...
   8: </Grid>

The best thing about Label's Target property is not only it sets focus to its pair control, but can also pose as a bridge back to the Label when we need to provide some feedback from the target control. For example, when a TextBox gets disabled,  we would want the associated Label render disabled as well. This is fairly easy to achieve through binding. All we need is a simple style for a label:

   1: <Style TargetType="{x:Type Label}">
   2:   <Setter Property="IsEnabled" Value="{Binding Path=Target.IsEnabled, RelativeSource={RelativeSource Self}}" />
   3: </Style>

The key is in binding's path, which queries target's IsEnabled property and sets it accordingly.

This opens up a range of possibilities. One of my favorite UI tricks is to visually differentiate the focused control from the others by slightly contrasting the label, associated with the focused control.  Label.Target is perfect for this.

I built on my previous example and the result now looks like this:

And here's the Label style I used:

   1: <Style TargetType="Label">
   2:   <Setter Property="Foreground" Value="{StaticResource LabelTextBrush}" />
   3:   <Style.Triggers>
   4:       <DataTrigger Binding="{Binding Path=Target.IsFocused, RelativeSource={RelativeSource Self}}" Value="True" >
   5:           <Setter Property="Control.Foreground" Value="{StaticResource FocusedLabelTextBrush}" />
   6:       </DataTrigger>
   7:   </Style.Triggers>
   8: </Style>

It's similar to the previous one, it just uses a DataTrigger to set Label's foreground color instead of direct property mapping.

I also added a short animation to make TextBoxes flash for a moment when they receive focus.

You can see all this in action by downloading and executing this Loose Xaml page.

Do it with Style!

In my previous post I've shown how to create a named brush resource in WPF, which can be used and reused through whole application. Although I gave a brush a meaningful name (WindowBackgroundBrush), it can as well be used to paint areas other than window backgrounds. Naming brushes this way is more of a visual hint to me: whenever I feel the need to change the looks of windows' background, the WindowBackgroundBrush would most likely catch my eye first. If you ever looked at the SystemColors class in Windows Forms (that's in System.Drawing namespace), this convention will feel familiar; the difference is that here we're dealing with brushes, while with SystemColors it's plain colors that we were using. To make the transition easier, the equally named class is also available in WPF (it's in System.Windows namespace). While still referencing all system colors, this new class incidentally includes additional properties to make those system colors available also as solid color brushes.

To conclude - creating custom brushes and naming it by their purpose is a lot like building a closed set of named colors you'll be using in your application. If you already have an idea of how your application should (visually) look like, or your designer has already come up with a theme or a style book, this kind of convention can constrain you to pre-chosen color set and and the same time keep you away from experimenting with some weird color combinations.

I really can't remember where I originally got this from, but whenever a hear a word style in the context of software development, application skinning is the first thing that comes to my mind. Skinning is basically a process of creating a visual theme for your application, where User Interface is built in a way that can be quickly changed simply by applying a new "skin" to it. And while WPF styles can by all means help you built skinable application, they are so much more than that.

To put it simple - WPF styles are sets of properties, which can be applied to a named element or a specific element type. A style can specify any property that a target object allows setting, no matter if it affect its visual rendering. For example, I might have a style which sets textbox's background and text color, and at the same time limits the length of inputted text by setting its MaximumLength property:

<Style x:Key="MyTextBoxStyle" TargetType="{x:Type TextBox}">
  <Setter Property="Foreground" Value="Yellow" />
  <Setter Property="Background" Value="Black" />
  <Setter Property="MaxLength" Value="10" />

Knowing what a simple style can do, we can return to the code snippet from the previous post. Remember - the goal was to specify how window's background should be painted without setting the Background property directly. Here's current page's full XAML:

    <LinearGradientBrush x:Key="WindowBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
      <GradientStop Color="#FF333333" Offset="0.0" />
      <GradientStop Color="#FF595959" Offset="1.0" />
    <Style TargetType="{x:Type Page}">
      <Setter Property="Background" Value="{StaticResource WindowBackgroundBrush}" />

Notice that I'm no longer setting Page's Background property. This is now done through style (marked bold part above) - by not specifying the key of the style, this style will be applied to Page elements within the style's scope. In this example, the scope is the current page, but if we were to move the style to the application level resources, it would be applied to all Pages within application, which don't explicitly specify some other style. We'll show how this works when this sample "application" gets a bit more complex.

OK, we now defined a brush and a style, which uses that brush to paint the window's background. We're now able to control how window gets painted without even touching the code for it. All we have to do is modify a style. And if we delete the style completely, guess what... the window will get painted with the default system color.

And this is how application looks so far. It's a loose Xaml page so you need .NET FX 3.0 to view it.

In the beginning, it was Black

This is the first post of what I would like to believe will be a series of thoughts on creating a good User Experience with Windows Presentation Foundation. I have no idea where this will take me, but I'll start with a color.

You like black? We've got black.


How about using it as a background color in a WPF application?


That's a nice black page, isn't it? But wait a minute! Is this way of hardcoding the color into the Page really a good idea? What options do we have here?

First, it's important to know that when setting Background="Black" in XAML, it's a solid black brush that you're actually setting to the Background property. This is possible with the help of a type converter called BrushConverter, which is responsible for creating a brush from as many string representations of a color as possible.

Now we're talking brushes... There are six kinds of brushes in WPF and we'll eventually get to know and use all of them. For now, it's the SolidColorBrush we're interested in [no need explaining what this one looks like I presume].

So, instead of painting our background with a solid black color, we can just paint it with "a brush" and define what "a brush" looks like elsewhere:

  Background="{DynamicResource WindowBackgroundBrush}">
      <SolidColorBrush x:Key="WindowBackgroundBrush" Color="Black" />

In this example, the solid black brush is defined within Page's resources and you probably noticed that it's got a new name now. We're not calling it by its color anymore; from now on we'll be addressing it by its purpose - to paint a window's background. This kind of abstracting away from the actual color is important because a week or two from now you might want to rethink your previous color choice and change it to some other color. You don't believe me? Just ask your wife...

In fact, pitch black color is not the perfect choice for an application window's back color anyway. We'll probably make the user's eyes more happy by putting some light in it, for example:

<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FF595959" />

Note that the color is now specified with the "webby" hexadecimal code.

If you're an adventurous type and like fancy design, you may even consider using a linear gradient brush, which will blend two or more colors across a line, pointed at whichever direction you like. You can even specify gradient stop points to customize the color transition lengths. The following construct uses two shades of dark gray to create a linear vertical gradient:

<LinearGradientBrush x:Key="WindowBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
  <GradientStop Color="#FF333333" Offset="0.0" />
  <GradientStop Color="#FF595959" Offset="1.0" />

Notice that the name of the brush remains the same as before, therefore we don't need to touch the rest of the code. The page still gets painted just by "a brush". While that might be the end of the story for some, the others would ask themselves - "OK, but what if I don't want to paint the background at all?"

And that's where WPF Styles kick in... I'll address that in my next post.