Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

VSM4WPF

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.

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.

Mix'n'stuff

As expected, a lot of stuff was shown and discussed on the MIX08 keynote today:

  • eight - Internet Explorer 8 Beta 1 (download): better standards compliance, backward compatible mode, faster faster JavaScript implementation, embedded debugging tools, "activities" and "webslices" (custom extensions, deliverable simply by hacking up a couple of rows of XML),. ...
  • Silverlight 2.0 Beta 1 (download): it's here! With only 4.3MB in size, it delivers highly anticipated UI controls, along with a new testing framework, including tests for all Silverlight controls. Supports isolated storage for offline caching. Plus, Silverlight 2.0 now ships with a non-commercial Go-Live license and will also run on Nokia [Symbian] phones. Finally, if you've done any work with Silverlight 1.1, you're in for a serious code rewriting, as there's a lot of breaking changes in the code base. [That's, however, a good thing, because these changes bring Silverlight's programming model much closer to the the one in WPF]
  • Expression Blend 2.5 March 2008 Preview (download): Silverlight 2.0 Support
  • Silverlight Tools Beta 1 for Visual Studio 2008 (download): Add-on to Visual Studio for Silverlight 2.0 Beta 1 development. Better designer experience, although far from being nice as in Expression Blend.
  • Sea Dragon in action - Deep Zoom: take a look: Hard Rock Memorabilia [a bit quirky at the moment, I'm afraid] Want to make your own Deep Zoom creation? Download Deep Zoom Composer preview. And you can start with this User Guide.
  • The future of WPF: new controls, performance improvements, etc...

Watch the MIX08 keynote recording here.

[Update: here's a great preview of Silverlight 2.0 Beta 1 controls in action by Kathy Kam. Note that these controls are available in source code w/ full unit tests]

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.

You've got mail: Windows Forms &amp; WPF interop

One of my favorite samples when talking about WPF is showing a rotating 3D letter 'e' in a Windows Forms application. You know, something like those "you've got mail" computer messages, seen in many Hollywood movies. Windows Forms/WPF interoperability features make this kind of stunt very easy to pull off and this is the recipe to make in happen in 15 minutes...

First, you'll have to come up with some kind of 3D element, which you can import in WPF. I used electric rain's ZAM 3D tool, which has the ability to export 3D elements directly to XAML, which can be later picked up and additionally arranged with  Expression Blend, for example. It actually took me just a couple of minutes to create a 3D letter 'e' and import the scene into Blend.

blendmail1

Rotating the 3D element was done by animating ViewPort's camera by setting 5 progressive key frames of its Rotate Transform property.

image

We need to make the element reusable, so we'll transform it to a user control. Expression Blend 2 (currently still in CTP version) fortunately makes this task very easy by exposing the "Make Control" task (Tools | Make Control...)

OK, half done... We now have a user control with rotating 3D element and a WPF Window, simply displaying it.

The next step is adding a new Windows Form to the project. Save the project in Blend, switch over to Visual Studio (2008) and add a new Form. Visual Studio will make sure all necessary interop assemblies will be added to the project in this process.

With newly created form displayed in the designer area and open a Toolbox. Right at the top (or elsewhere, depending on your project's name), there should be your WPF user control, ready to drag onto the form. When doing so, Visual Studio will create your control, hosted in the ElementHost control (a Windows Forms control, which can host a WPF element). Set control's size to a desired value and you're done.

image

Download the sample project here.

WPF tutorials

If you're starting your development with Windows Presentation Foundation, head over to windowsclient.net, as they're running a great video tutorial series on WPF app development.

Another exhaustive tutorials on designing WPF applications with Expression Blend can be found on the Expression Blend and Design Blog.

And while visiting windowsclient.net, you might as well check out recently released Syndicated Client Experiences Starter Kit & Reader SDK. Remember New York Times Reader? With the SCE starter kit you can build similar experience for delivering your own content to the reader. I have a pretty fixed idea for using this, all I have to do now is find some extra time to pursue it. Anyway, another useful implementation of the SDK is the MSDN Magazine Reader, which also comes with the full source code.