Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

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:

image 
[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" />
</Style>

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:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Page.Resources>
    <LinearGradientBrush x:Key="WindowBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
      <GradientStop Color="#FF333333" Offset="0.0" />
      <GradientStop Color="#FF595959" Offset="1.0" />
    </LinearGradientBrush>
    <Style TargetType="{x:Type Page}">
      <Setter Property="Background" Value="{StaticResource WindowBackgroundBrush}" />
    </Style>
  </Page.Resources>
</Page>

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.

Black

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

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Background="Black">
</Page>

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:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Background="{DynamicResource WindowBackgroundBrush}">
  <Page.Resources>
      <SolidColorBrush x:Key="WindowBackgroundBrush" Color="Black" />
  </Page.Resources>
</Page>

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" />
</LinearGradientBrush>

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.

Experience new Silverlight skins

Corrina Barber posted a cool looking new skin for Silverlight controls, which indeed looks perfect for giving your application a sketchy appearance when in early stages of development.

However, if you don't find the green color she used sketchy enough, it doesn't get any easier to adjust it to your likings. When we're talking about control skins in WPF/Silverlight, we're talking about styles, right? So...

with a simple Search & Replace in the App.Xaml file she posted along with her sample, I changed some of the colors in her skins to get a bit more of a Black & White / Gray appearance:

Silverlight skin 

Now imagine, how much "damage" you could do to this skin with Expression Blend...

Anyway, this is the fourth Silverlight skin she posted and she's not stopping. If not anything else, this is a great inspiration to start creating your own Silverlight skins!

Silverlight 2.0: Creating a basic animation through code

In my previous Silverlight post, I mentioned Silverlight 2.0 API now allows creating animations through code. While this wasn't possible with Silverlight 1.1 Alpha [you would have to create of piece of Xaml, declaring a storyboard with all animations markup, then load it into a Storyboard object by using XamlReader.Load() method], Silverlight 2.0 now makes it pretty easy.

The following animation code will create very basic fade out effect for given element, animating the Opacity property from 1 to 0 in one second:

private DoubleAnimation CreateFadeOutAnimation(string elementName)
{
    DoubleAnimation animation = new DoubleAnimation();
    Storyboard.SetTargetName(animation, elementName);
    Storyboard.SetTargetProperty(animation, "Opacity");
    animation.To = 0;
    animation.Duration = new Duration(TimeSpan.FromSeconds(1));
    return animation;
}
To start this animation, you'll have to add it to a new storyboard first:
Storyboard sb = new Storyboard();
sb.Children.Add(CreateFadeOutAnimation("myElement"));
sb.Duration = new Duration(TimeSpan.FromSeconds(1));
sb.Completed += new EventHandler(sb_Completed);
LayoutRoot.Resources.Add(sb);
sb.Begin();

The "myElement" above is the name of an visual element with this name, which has to exist in the context of the storyboard for it see it. Storyboard is added to the LayoutRoot's resources [LayoutRoot is the name of a default root Grid in Silverlight]. Instead of passing just a name of an element, you could as well pass in the actual element you're animating.

Note the Completed event hookup up there. This is because we want to stop and remove the animation from the resources when animation is done to clean things up a bit. Here's the handler:

void sb_Completed(object sender, EventArgs e)
{
Storyboard sb = (Storyboard)sender; sb.Stop(); this.Resources.Remove(sb); }

That's it. Of course you can add as many animations to the storyboard as you want - animating different elements at the same time, adding different animations, etc... In further posts we might add some more complexity to this basic sample.

How well do you know your Culture?

When doing code reviews, I often stumble upon a piece of code with some culture-specific information hard-coded in it. One example of this being month names:

string[] months =
   
{
        "January",
       
"February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
       
"October",
        "November",
        "December"
   
};

This is all fine if your application is intended for English spoken users and all that, but hey - why try and duplicate something, what's already been done for you? CultureInfo class has all the information you need:

string[] months = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;

And if you need the name of the months in some other supported language, all you have to do is ask [this one's for Slovenia):

string[] months = CultureInfo.GetCultureInfo("sl-SI").DateTimeFormat.MonthNames;

Then again, if all you need is month names in shortened form, the class can also help:

string[] months = CultureInfo.CurrentCulture.DateTimeFormat.AbbreviatedMonthNames;

If you're after just one specific month name, it will bi provided for you [the following line will get you February - obviously]:

string month = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(2);

And so on... The same pattern applies for day names, etc. If there is anything specific that you would want to know about a certain culture, CultureInfo class will give you all the information you need. Given these possibilities, one can even create a custom culture using the CultureAndRegionInfoBuilder class. There's quite a few examples of where this would come in useful.

One thing to note though: The MonthNames properties described above will return you the string array of 13 items; although majority of cultures have 12 months in a year, a few apparently have 13, so be aware of that when using these properties. If month names list is intended for a data source that can be bound to, you may want to return the actual number of months. The following method will return the actual number of months in a given year:

int mothCount = CultureInfo.CurrentCulture.DateTimeFormat.Calendar.GetMonthsInYear(DateTime.Today.Year);

The other way would be just skipping the empty months. There are again, several ways to do this - today, the weapon of choice is fashionable - Linq [or rather - its extensions], although it's most likely not the fastest way of doing it:

string[] cultureMonths = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;
string[] months = cultureMonths.TakeWhile<string>(month => month.Length > 0).ToArray<string>();

The TakeWhile method will return only those items, for which lambda expression would return true. Also not that I could as easy replace the ToArray<string>() method at the end with ToList<string>() and return a generic list of strings:

List<string> months = cultureMonths.TakeWhile<string>(month => month.Length > 0).ToList<string>();

... but since this is most likely a read-only list, it doesn't really matter.

Make your application speak

.NET Framework 2.0 simplified the way of playing audio files from desktop applications. .NET Framework 3.0 takes this one step further by introducing the speech API, residing in the System.Speech namespace (it's basically a wrapper around Microsoft SAPI and is packed in System.Speech.Dll).

Using the SpeechSynthesizer class you can make your computer actually speak the text you feed to it:

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.Speak("Hello world!");

If you don't want to stop your application from blocking the execution while speaking, this is there's the asynchronous equivalent to this method:

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SpeakAsync("Hello universe!");

The class provides a lot of ways of influencing the sound, like changing the rate, volume, providing hints on pronunciation, including existing sounds and changing the voice. Windows Vista comes with the preinstalled voice called Microsoft Anna, while Microsoft Sam should be available on Windows XP.

OK, so I thought I would update my You've got mail application sample by including some spoken text when new mail "arrives". This is the code I used:

PromptBuilder builder = new PromptBuilder();
builder.AppendAudio(new Uri(@"file://\windows\media\windows notify.wav"));
builder.AppendBreak(PromptBreak.Small);
builder.AppendText("You've got mail.");
builder.AppendBreak(PromptBreak.Small);
builder.AppendText("I think it's from your... wife.");

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SpeakAsync(builder);

And this is the extended You've got mail sample project for download.

Enjoy. A couple of notes though: The speech API does not require you to build a WPF to use it. You can also use it from Windows Forms or a Console application, just as long as you're targeting .NET FX 3.0. And don't forget to reference the System.Speech.Dll.

You've got mail

Paste as Xaml Visual Studio Add-In

Common Windows Presentation Foundation controls don't necessarily provide an intuitive path for upgrading from their Windows Forms equivalents. Take, for example, the RichTextBox control - there is no Rtf property for setting and getting RTF formatted text in WPF's RichTextBox. You can however, still load the RTF text into RichTextBox, using this method (loading RTF text from an embedded resource called MyRtfText):

ASCIIEncoding encoding = new ASCIIEncoding();
byte[] bytes = encoding.GetBytes(Properties.Resources.MyRtfText);

using (MemoryStream s = new MemoryStream(bytes))
{
   
TextRange range = new TextRange(rtfBox.Document.ContentStart, rtfBox.Document.ContentEnd);
   
range.Load(s, DataFormats.Rtf);
}

But how about creating a couple of text lines that would fit right into WPF's RichTextBox? RichTextBox exposes the Document property, which would accept a FlowDocument - and that's a native WPF content element, persisted in Xaml format. If you need to insert a piece of document into RichTextBox at design time, you'll have to know some Xaml to to it. Having to convert some existing text from RTF or other rich text format (pasting from Word seems like a good idea) requires a converter...

Luckily, such a converter is already built in WPF - it's the RichTextBox itself! The following snippet will stuff the text from the clipboard (text format doesn't matter, as long it's text) into the RichTextBox and get it out as a FlowDocument:

RichTextBox box = new RichTextBox();
box.Paste();

string text;
TextRange range = new TextRange(box.Document.ContentStart, box.Document.ContentEnd);

using (MemoryStream stream = new MemoryStream())
{
   
range.Save(TextDataFormat.Xaml.ToString());
   
stream.Seek(0, SeekOrigin.Begin);
   
using (StreamReader reader = new StreamReader(stream))
   
{
        text = reader.ReadToEnd();
   
}
}

And this is the core of this very simple Visual Studio 2008 Add-In that I've created - it will allow you to paste any text from the clipboard into Visual Studio as XAML.

Installing the Add-In is as easy as copying a DLL, included in the zip file [see link below], into *\My Documents\Visual Studio 2008\Addins folder and (re)start Visual Studio 2008. You'll find the new command under Tools menu.

image 

Download the Add-In. Full Add-In source code will follow...

On a side note... WPF future looks bright: performance and VS Designer improvements, new setup framework, new controls (DataGrid, Ribbon, Calendar, ...) See this ScottGu's post for more details.