Diederik Krols

The XAML Brewer

Building WPF forms without GDI decoration

This article describes a base class for WPF windows. It hides all GDI chrome, without losing functionality. WPF promises entire freedom in look-and-feel of your application. In its standard configuration, however, a WPF Window is still hosted in a classic GDI-based WinForm. Its border and header are rendered by the operating system. This takes away a lot of styling opportunities: things like a custom close button or rounded borders become impossible. On top of that, the GDI chrome eats a lot of pixels away from your application. That waste of space becomes obvious if you use custom controls like the popular Ribbon.

I created the NoGdiWindow base class to solve all of these problems. The following screenshots from the attached sample application show the same WPF window - with and without using the base class. If you prefer the left window, you may stop reading now Smile.

before after

 

Hiding the GDI header

Setting the WindowStyle to System.Windows.WindowStyle.None removes the window header:

this.WindowStyle = System.Windows.WindowStyle.None;

You obviously loose the icon, the title and the minimize, maximize/restore, and close buttons. These are relatively easy to recover: the NoGdiWindow class contains the necessary commands and properties to rapidly create custom buttons in XAML. Here's an overview of the relevant class members:

Here's an example of a custom button:

<Button ToolTip="Maximize" Command="{Binding ElementName=Window, Path=MaximizeCommand}" Visibility="{Binding ElementName=Window, Path=MaximizeButtonVisibility}" />

Restoring the buttons is not sufficient: the beheaded window doesn't have a region anymore by which you can drag it, or minimize/restore by double-clicking. When using NoGdiWindow, all you need to do is create a region at the appropriate position and hook in the MouseLeftButtonDown event handler:

<Grid MouseLeftButtonDown="Header_MouseLeftButtonDown" Background="Transparent" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="32" Margin="80 0 0 0">

You may want to implement this functionality as a behavior instead of an event handler.

In the following screenshot, the region is highlighted. The left margin of 80 pixels keeps the ribbon's application menu accessible:

When you use WindowStyle.None your window will overlap the task bar if it's maximized. I personally don't mind at all. If you (or our end users) have a problem with this, you find some possible workarounds here.

Hiding the GDI border

You can make the remaining GDI border disappear by setting the AllowsTransparency property to True and your form's background to Transparent:

this.AllowsTransparency = true;
this.Background = new SolidColorBrush(Colors.Transparent);

This allows you to provide a rounded border around your window, or create an irregular shape. Unfortunately the native GDI border also hosts the resize handles, so you need to get these back. The NoGdiWindow draws a series of rectangles on the form, with the necessary mouse down handlers. Therefor, your main panel should be a Grid. In the following screenshot these rectangles are highlighted:

When the window is opened, it fetches its Win32 handle:

this.hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;

When you hold the left mouse button inside one of the resize rectangles, the resize message is sent to the operating system through a SendMessage call:

SendMessage(this.hwndSource.Handle, 0x112, (IntPtr)(61440 + direction), IntPtr.Zero);

The resize code is based on this article by Joshua. Here's an overview of the relevant class members:

The AllowsTransparency is implemented through a technique called 'layered windows'. If you type these keywords in your [insert favorite search engine here], you'll immediately see that there are some issues under Windows XP. Your user interface may run without hardware acceleration on older XP releases, and it definitely ruins some WPF controls (tooltips, popups, comboboxes). There there are also issues with WindowsFormHost controls, regardless of the operating system you use. NoGdiWindow is aware or this, and has some defensive code around the property:

if ((Environment.OSVersion.Version.Major > 5) & (!this.UsesWindowsFormsHost))
 {
    // Activate Transparency
  // ...
 }

Code

Here's the sample project :U2UConsult.WPF.NoGdiWindow.zip (1.31 mb)

Enjoy!

Using the Prism 4.0 Event Aggregator

This article illustrates the problems that occur when you use regular events for intercomponent communication in a composite application. It shows how to solve these problems by implementing the Mediator design pattern, using the Event Aggregator from the Prism 4.0 framework as an example.

Composite applications

A composite application draws its functionality from a set of as-loosely-as-possible-coupled functional modules. At runtime, these modules are loaded into an application shell that provides common non-functional services, such as security, screen layout, and localization. The Managed Extensibility Framework (MEF) simplifies the design and development of this type of applications by providing module discoverability and composition capabilities:

Discoverability

Types that want to be discovered by MEF indicate this by using attributes. The following code snippets from the attached Visual Studio project show how a publisher and a subscriber make themselves available to the outside world (i.c. a viewmodel that will hook them together):

[Export]

public class Subscriber : INotifyPropertyChanged

{

    // ...

}

[Export(typeof(IPublisher))]

public class Publisher : IPublisher

{

    // ...

}

Composition

At runtime, the application's object graph is constructed by the so-called composition. All the application needs to do, is decorating the required parts with attributes. This is how the viewmodels in the sample project request for a publisher and a subscriber:

[Import]

public IPublisher Publisher { get; set; }

 

[Import]

public Subscriber Subscriber { get; set; }

The exported parts are looked up by MEF in catalogs, placed in a container, and then bound to the corresponding imports:

AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

CompositionContainer container = new CompositionContainer(catalog);

container.ComposeParts(this);

MVVM

Despite its strict modularity, a composite application is not really different from any other enterprise application that you would build in WPF, Silverlight, or WP7. For maintainability and testability purposes it definitely makes sense to develop the modules as well as the shell according to the MVVM-pattern. You'll end up with an application architecture that looks like a grid: functionality is layered vertically into modules, and technicality is layered horizontally into views, viewmodels, and models:

Both axes should maintain a level of independence between constituants: individual modules may make no assumptions about other modules, and within a module the models shouldn't know their viewmodels, viewmodels shouldn't know their views, and views should have no code beside.

The attached sample project has a simplified version of this architecture: it does everything in one project. It is however representative: all objects are injected through MEF, and the application is strictly MVVM. Here's a screenshot:

Communication

When the composite application is running, some components living in different architectural cells would want to talk to each other, e.g. viewmodels from different modules would want to play their role in an application-wide publisher-subscriber scenario. An implementation based on .NET events seems the obvious choice here.

Regular Events

Unfortunately, regular events require a reference from the subscriber to the publisher - at least while registering the event handler. After that, the subscriber doesn't need that reference to the publisher anymore. But even if you throw it away, the objects stay tightly connected: the publisher holds a reference to the subscriber in its delegate, as the 'target' of the method:

This prevents the subscriber from being garbage collected even if the rest of the application isn't referencing it anymore. You can verify this easily by running the sample project. After you 'kill' the regular event subscriber, it will remain in memory:

The only way to clean up memory is to unregister the event handler, e.g. in a Dispose action. Unfortunately this implies that the subscriber should hold a permanent reference to the publisher, now preventing the publisher to be cleaned up. In this scenario you should also exactly know when to dispose the subscriber. In a lot of cases -especially in composite applications- this is simply not possible.

EventAggregator

What you need in a composite application is a kind of central chat room, where all components anonymously appear, communicate, and disappear. This is exactly what the classic Gang-of-Four Mediator design pattern does: it describes how to moderate communication between components that aren't aware of each other's identity. The Prism 4.0 Event Aggregator is a robust implemenation of this design pattern. Prism is a framework and a set of guidelines on building composite applications in WPF, Silverlight, and WP7. You'll find more info here.

In our sample application, the publisher and subscriber need to get a reference to a central event aggregator. We'll use MEF to do this.

First the publisher and subscriber need to add the event aggregator to their list of required parts:

[Import]

public EventAggregator EventAggregator

{

    get { return this.eventAggregator; }

    set { this.eventAggregator = value; }

}

Then you have to make sure that the event aggregator becomes available, e.g. by explicitly adding it to the MEF container (Prism has other ways to do this):

AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

CompositionContainer container = new CompositionContainer(catalog);

var batch = new CompositionBatch();

batch.AddExportedValue<EventAggregator>(new EventAggregator());

container.Compose(batch);

container.ComposeParts(this);

Now it's time to define the event's payload type - a Prism requirement:

using Microsoft.Practices.Prism.Events;

 

public class PublishedEvent : CompositePresentationEvent<object>

{

}

The publisher publishes an event with the following two lines:

PublishedEvent pe = this.eventAggregator.GetEvent<PublishedEvent>();

pe.Publish(null);

In the subscriber, registering an event is also a two-liner:

PublishedEvent pe = this.eventAggregator.GetEvent<PublishedEvent>();

pe.Subscribe(o => this.Publisher_Published(o));

The event aggregator holds publishers and subscribers together via weak references, allowing participants to disappear without memory leaks. 'Killing' the subscriber in the sample application, will release its memory:

Extra's

I hope you're convinced of the need for a communication Mediator in some of your applications. If you go for Prism's event aggregator, you'll get a couple of extra's.

  • In some cases it's necessary to 'upgrade' the default weak reference to a strong one. You can do this by setting the second parameter in the registration method to 'true':

pe.Subscribe(

    o => this.Publisher_Published(o),

    true);

  • A subscriber can specify on which thread he wants to be notified. This is handy when the event handler needs the UI thread. In a viewmodel from a MVVM application this should never be the case: the bindings should take care of this.
  • Lastly, you can apply a filter on the subscription, so that some events will be ignored. The following -I admit: silly- example ignores events raised during 'odd' minutes:

pe.Subscribe(

    o => this.Publisher_Published(o),

    ThreadOption.PublisherThread,

    false,

    o => DateTime.Now.Minute % 2 == 0);

Source code

Here's the source, the whole source, and nothing but the source: U2UConsult.Composite.Communication.Sample.zip (619,46 kb)

Enjoy!

T9 encoding, decoding and prediction in C#

T9 stands for Text on 9 keys. It's the -patented- mobile phone technology that allows words in SMS messages to be entered by a single keypress for each letter. So instead of pressing the '3'-key three times to enter an 'f', you press the key only once. The software will then try to figure out whether you wanted a 'd', an 'e', or an 'f' by looking up your input in its dictionary and make an educated guess. T9 technology allows you to rapidly enter text on a numerical keypad, but also on a small touch panel like a smart phone or an iThing. Even on larger touch screens the technology is useful: it allows the input region for free text to be as small as possible. In a lot of applications, displaying a full touch keyboard would just take too much screen infrastructure.

Encoding: from clear text to T9

The text you enter via the key pad or touch screen will be encoded to the T9 format, and compared to the internal dictionary. That dictionary contains sentences, words, or fragments (n-grams). That dictionary is indexed by the T9-encoded version of the text value. So the encoding algorithm is called while you're inputting text, but also when building or updating the dictionary.

Text Normalization

The first step in T9-encoding is text normalization, which translates the input to the 26 characters of the alphabet. The only hard part here is removing the so-called diacritics, markers like

  • accent: déjà becomes deja,
  • cedilla: façade becomes facade, and
  • diaeresis: Noël becomes Noel.

Fortunately there's a method in .NET that does this for us: the String.Normalize() method, with an overload that takes a Unicode normalization form as parameter. Here's a sample C# routine to remove the diacritics from an input string:

/// <summary>

/// Normalizes a string and removes diacritics.

/// </summary>

public string RemoveDiacritics(string clearText)

{

    string normalizedText = clearText.Normalize(NormalizationForm.FormD);

 

    StringBuilder sb = new StringBuilder();

    foreach (char ch in normalizedText)

    {

        UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(ch);

        if (uc != UnicodeCategory.NonSpacingMark)

        {

            sb.Append(ch);

        }

    }

 

    return sb.ToString().Normalize(NormalizationForm.FormC);

}

Here's a screenshot from the included sample project:

Text Encoding

Once the text is normalized to the 26 alphabetic characters, the rest of the encoding is a piece of cake: 'a', 'b' and 'c' will be mapped to '2' etc. We'll use a train of regular expressions to do this:

/// <summary>

/// Encodes a string to the T9 format.

/// </summary>

public string EncodeString(string clearText)

{

    // Normalize and convert to lowercase.

    string result = this.RemoveDiacritics(clearText).ToLower();

 

    // Remove digits.

    result = Regex.Replace(result, "[2-9]", string.Empty);

 

    // Translate to SMS.

    result = Regex.Replace(result, "[abc]", "2");

    result = Regex.Replace(result, "[def]", "3");

    result = Regex.Replace(result, "[ghi]", "4");

    result = Regex.Replace(result, "[jkl]", "5");

    result = Regex.Replace(result, "[mno]", "6");

    result = Regex.Replace(result, "[pqrs]", "7");

    result = Regex.Replace(result, "[tuv]", "8");

    result = Regex.Replace(result, "[wxyz]", "9");

 

    // Replace remaining non-SMS characters by word boundary.

    result = Regex.Replace(result, "[^2-9]", " ");

 

    return result;

}

Here's again a screenshot from the included demo application:

Using the dictionary

You can trigger the decoding of a single word when a word boundary character is entered (with the '1' button). The included sample program takes a simpler approach: it triggers the decoding algorithm when length of the input text reaches 4. This is because the internal dictionary is specialized in four-letter words (you know: the words your wife doesn't like you to use at home, like dust, wash, cook, and iron) . The included dictionary contains more than 600 four-letter words.

Text decoding

T9-encoding is not directly reversible: an encoded T9-string represents many alphanumerical strings. Most of these letter combinations will not be in your internal dictionary of known words or sentences. The decoding boils down to a lookup in the dictionary. Here's the source of the decoding method in the included sample project. The call may return 0, 1, or more candidates:

/// <summary>

/// Decodes a T9 string to a word in the dictionary.

/// </summary>

public List<string> DecodeString(string t9Text)

{

    return (from w in this.dictionary

            where w.Key == t9Text

            select w.Value).ToList();

}

Here's the function in action:

Text prediction

The real strenght in T9-ish technologies lies in the prediction capabilities. An engine able to auto-complete your input, will save you a lot of time. This is where you will need to strike a balance between speed and functionality. The larger the dictionary and the more flexibility you introduce (n-grams, fuzzy lookups using different edit distance algorithms, phonetic search), the slower the response time becomes. The included project has a simplistic prediction routine, based on the prefix. Again it returns a list, which may be empty:

/// <summary>

/// Predicts a T9 decoding, based on a prefix.

/// </summary>

public List<string> Predict(string prefix)

{

    return (from w in this.dictionary

            where w.Key.StartsWith(prefix)

            select w.Value).ToList();

}

Here's a screenshot of it:

Source code

Here's the whole project. It's a nice little WPF MVVM application: U2UConsult.T9.Sample.zip (93,09 kb)

By the way, the app is not touch-enabled (they're real buttons ;-).

Enjoy!

Essential WPF ListBox Styling

This article explains how to style a WPF ListBox. I know: there must be a million articles about this subject. So if you're looking for kaleidoscopic brushes, dazzling effects, and animations from outer space, then feel free to press the Back button in your browser to return to your search engine page, and click the next hit. If however you're interested in some details on how to put the cherry on the templated ListBox cake, then please continue reading.

 

Styling the content

The first step in styling any list control is creating a data template for the list items. So let's get it over with.

A simple data template

The list control will be populated with objects with properties (obviously, because there's nothing else in .NET ;-). The following data template displays the name property of its source. The DataType property in the XAML is mandatory and then ignored.

<DataTemplate

   x:Key="RockstarTemplate"

   DataType="Whatever">

    <Border

       x:Name="TheBorder"

       BorderBrush="Gray"

       BorderThickness="1"

       Padding="4"

       CornerRadius="4"

       Margin="2">

        <TextBlock

           Text="{Binding Name}"

           Width="320">

        </TextBlock>

        <Border.Background>

            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                <GradientStop Color="AliceBlue" Offset="0.15" />

                <GradientStop Color="White" Offset="0.85" />

                <GradientStop Color="Lavender" Offset="1" />

            </LinearGradientBrush>

        </Border.Background>

    </Border>

</DataTemplate>

 

Styling the selected items

The selected items deserve to be highlighted, so we define an extra brush for these:

<LinearGradientBrush

   x:Key="SelectedItemBrush"

   EndPoint="0.5,1" StartPoint="0.5,0">

    <GradientStop Color="Lavender" Offset="0.15" />

    <GradientStop Color="AliceBlue" Offset="0.85" />

    <GradientStop Color="CadetBlue" Offset="1" />

</LinearGradientBrush>

The following code applies the brush through a data trigger. The XAML is quite complex, but very clear. We walk up the visual tree to discover the parent list box item, and apply the brush if it IsSelected:

<DataTemplate.Triggers>

    <DataTrigger

       Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}"

       Value="True">

        <Setter

           TargetName="TheBorder"

           Property="Background"

           Value="{StaticResource SelectedItemBrush}" />

    </DataTrigger>

</DataTemplate.Triggers>

This is as far as I will go regarding data templates. Check out the WPF Themes at CodePlex for some good in-depth data template examples.

Apply the template

Here's how to apply the template to a listbox:

<ListBox

   x:Name="ItemTemplateBox"

   ItemTemplate="{StaticResource RockstarTemplate}"

   BorderBrush="Transparent"

   Background="Transparent"           

   />

 

Styling the listbox itself

A data template is not enough

Creating the data template is the fun part. Here is were most blog and other articles end - leaving you in frustration. Because just applying a data template to style a listbox's items is not sufficient to provide a nice user experience. Here's how the current listbox -with just a data template- looks like when running the application:

Even when the focus went to another control, the data-template-only listbox shows unwanted side effects:

Actually, some important looks of the selected list item(s) are not defined in the data template itself, including:

  • the (blue) background color,
  • the (white) foreground color, and
  • the dotted border to express keyboard focus.

While it's possible to improve the looks by tweaking the data template (e.g. by using negative padding), the right place to style these settings is the parent listbox itself.

Where are the original control templates?

The XAML resource dictionaries for the builtin themes (Classic, Aero, ...) can be found here at MSDN (4.0 versions apparently are not yet available). The source code of the themes also come with Expression Blend (search for the SystemThemes folder), and can be found in a lot of other places. If you open one of these files and search for the ListBoxItem styles, you'll find stuf like this:

<Setter Property="Padding"

       Value="2,0,0,0"/>

This code is responsible for that horrible thin blue line on the left side of your data template.

In the default XAML template for ListBoxItem you'll also find this trigger:

<Trigger Property="IsSelected"

           Value="true">

    <Setter TargetName="Bd"

           Property="Background"

           Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>

    <Setter Property="Foreground"

           Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>

</Trigger>

Here's where the blue background and the white text color comes from.

Overriding default brushes

Instead of redefining the whole ListBoxItem style, you can easily get away with overriding the brushes that are used as static resource. You can use the following XAML to make the unwanted stylings disappear:

<ListBox.Resources>

    <!-- Style used if item is selected and listbox has keyboard focus -->

    <Style x:Key="NoFocusVisualStyle" TargetType="Control">

        <Setter Property="BorderBrush" Value="Transparent" />

    </Style>

    <!-- Apply this style -->

    <Style x:Key="{x:Type ListBoxItem}" TargetType="ListBoxItem">

        <Setter Property="FocusVisualStyle" Value="{StaticResource NoFocusVisualStyle}" />

    </Style>

    <!-- Color used if item is selected and listbox has focus -->

    <SolidColorBrush

       x:Key="{x:Static SystemColors.HighlightBrushKey}"

       Color="Transparent"/>

    <!-- Color used if item is selected and listbox does not have focus -->

    <SolidColorBrush

       x:Key="{x:Static SystemColors.ControlBrushKey}"

       Color="Transparent"/>

    <!-- Font color used if item is selected and listbox has focus -->

    <SolidColorBrush

       x:Key="{x:Static SystemColors.HighlightTextBrushKey}" 

       Color="Black" />

</ListBox.Resources>

 

Empty data

Unfortunately WPF controls don't have an EmptyDataTemplate property like their ASP.NET siblings. The empty data template describes how the list control looks like when it's bound to an empty data source.

In WPF we have to build this ourselves. Let's keep things simple and display a TextBox in front of the ListBox, and bind its visibility to the items count of the ListBox.

Here's the XAML:

<Grid>

    <ListBox

    ...

    </ListBox>

    <TextBlock

       Margin="4"

       FontStyle="Italic"

       Text="No data found..."

       Grid.Row="0" Grid.Column="1" Grid.RowSpan="2">

        <TextBlock.Style>

            <Style TargetType="{x:Type TextBlock}">

                <Setter Property="Visibility" Value="Collapsed" />

                <Style.Triggers>

                    <DataTrigger Binding="{Binding ElementName=EmptyTemplateBox, Path=Items.Count}" Value="0">

                        <Setter Property="Visibility" Value="Visible" />

                    </DataTrigger>  

                </Style.Triggers>

            </Style>                            

        </TextBlock.Style>

    </TextBlock>

</Grid>

Here's how it looks like when the app runs: 

Source Code

As usual, here's a working sample: U2UConsult.WPF.Template.Sample.zip (17,81 kb)

Enjoy!

A Rich HTML TextBlock for WPF

This article -proudly- presents a WPF control that displays rich text from an HTML source: it has a Text dependency property that you can bind to a HTML-formatted string. It's designed to display -not edit- rich information messages like warnings, error messages, and other feedback e.g. from a localizable resource file. Here are a couple of examples, on the left side is the original HTML, on the right side is how it's displayed by the control:

Formatting:

Font sizes:

Colors:

Some issues with WPF's native RichTextBox control.

The HtmlTextBlock control is based on WPF's native RichTextBox control. This was not an obvious choice, since RichTextBox was actually designed as an editor control: by typing in the box and pressing toolbar buttons, a FlowDocument is created and displayed. This FlowDocument is accessible through the Document property, which unfortunately is

  • very complex to manipulate, compared to a formatted HTML or XAML string (you can't store it in a resource file), and
  • not a dependency property.

On the other hand, the FlowDocument has powerful text formatting features, so it really makes sense to try to leverage these.

Making a bindable RichTextBox

If you grab your favorite search engine and type "WPF Bindable RichTextBox" you'll find plenty of implementations. This one on CodePlex nicely explains the problems ànd solutions. Basically all you need to do is write a dependency property that is wrapped around the RichtTextBox' FlowDocument whilst converting it to and from a XAML-formatted string. Here's how this process looks like in code:

Dependency Property

These code snippets define the dependency property:

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(

    "Text",

    typeof(string),

    typeof(RichTextBox),

    new FrameworkPropertyMetadata(

        String.Empty,

        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,

        new PropertyChangedCallback(OnTextPropertyChanged),

        new CoerceValueCallback(CoerceTextProperty),

        true,

        System.Windows.Data.UpdateSourceTrigger.LostFocus));

 

public string Text

{

    get { return (string)GetValue(TextProperty); }

    set { SetValue(TextProperty, value); }

}

Conversion from XAML to FlowDocument

This method takes a XAML-formatted string and loads it into a FlowDocument:

public void SetText(System.Windows.Documents.FlowDocument document, string text)

{

    try

    {

        TextRange tr = new TextRange(document.ContentStart, document.ContentEnd);

        using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(text)))

        {

            tr.Load(ms, DataFormats.Xaml);

        }

    }

    catch

    {

        throw new InvalidDataException("data provided is not in the correct Xaml format.");

    }

}

Conversion from FlowDocument to XAML

This function does the opposite. It saves a FlowDocument as a XAML-formatted string:

public string GetText(System.Windows.Documents.FlowDocument document)

{

    TextRange tr = new TextRange(document.ContentStart, document.ContentEnd);

    using (MemoryStream ms = new MemoryStream())

    {

        tr.Save(ms, DataFormats.Xaml);

        return ASCIIEncoding.Default.GetString(ms.ToArray());

    }

}

The above code snippets originate from this RichtTextBox implementation from CodePlex (more about that later).

From TextBox to TextBlock

Since my control is a display panel instead of an edit box, I had to tweak the code in several places. Some extra properties were set in the constructor:

public RichTextBox()

{

    Loaded += RichTextBox_Loaded;

 

    //Added

    this.IsReadOnly = true;

    this.Focusable = false;

}

The original CodePlex control was not 100% percent bindable to a source: it was just Initializable from a source. After the source provided the initial value, all other updates were ignored. That was not compatible with my requirements: I wanted to bind the control to a dynamic value, like changing status information or an on-the-fly-localizable message. So I removed the code that inhibited long-term binding: the definition and all references and manipulation of the _textHasLoaded variable. Now the control does more, with less code.

All you need to do is bind the textbox to its source:

<uc:RichTextBox

   Text="{Binding Message}"

</uc:RichTextBox>

And on every update of the source, the displayed text will also be updated:

this.Message = "The report was sent to <b>your local printer</b>.<br/><br/>Press <u style='color:red'>Enter</u> to continue or <u style='color:red'>Back</u> to print again.";

 

Here's the result:

Converting HTML to XAML, and back

The native WPF RichTextBox nicely displays plain text, RTF, and XAML, but no HTML. Fortunately a lot of attempts were already made to convert HTML into XAML and back. The code I'm currently using comes from MSDN. Its probably not the world's best converter, but it simply does what I was looking for: formatting (bold, italic, underline, size, color, and line breaks). It's not the best solution if you want to properly display tables, lists, headers and so. A more powerful convertor can be found on CodePlex in the HTML 2 RTB XAML project, which in its turn is based on HTML Agility Pack. Unfortunately the conversion code in the former project is tightly coupled to (Silverlight) controls. I didn't have the time to refactor this. (Take that as a hint Smile)

Making the RichTextBox understand and speak HTML

The RichTextBox from the Extended WPF Toolkit -again from CodePlex- not only has a Text dependency property for data binding. It also introduces the concept of Text Formatters, allowing to declaratively and programmatically specify the format of the content. The three canonical Text Formatters are included; PlainTextFormatter, RtfFormatter, and XamlFormatter.

All I did was taking the code of the XamlFormatter and plugged in the Html converter. I also replaced the ASCII encoding by UTF8 encoding, since French text wasn't displayed correctly.

Here's the full code of the HTML-to-FlowDocument-and-back converter:

public class HtmlFormatter : ITextFormatter

{

    public string GetText(System.Windows.Documents.FlowDocument document)

    {

        TextRange tr = new TextRange(document.ContentStart, document.ContentEnd);

        using (MemoryStream ms = new MemoryStream())

        {

            tr.Save(ms, DataFormats.Xaml);

            return HtmlFromXamlConverter.ConvertXamlToHtml(UTF8Encoding.Default.GetString(ms.ToArray()));

        }

    }

 

    public void SetText(System.Windows.Documents.FlowDocument document, string text)

    {

        text = HtmlToXamlConverter.ConvertHtmlToXaml(text, false);

        try

        {

            TextRange tr = new TextRange(document.ContentStart, document.ContentEnd);

            using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text)))

            {

                tr.Load(ms, DataFormats.Xaml);

            }

        }

        catch

        {

            throw new InvalidDataException("data provided is not in the correct Html format.");

        }

    }

}

Architecture

The following UML class diagram reveals all major component of the architecture:

Source Code

The included project contains the control, and a sample client.

Here's how the client application looks like:

Here's the code: U2UConsult.HtmlTextBlock.Sample.zip (91,62 kb)

Enjoy!

Optimistic concurrency using a SQL DateTime in Entity Framework 4.0

This article explains how to implement optimistic concurrency checking using a SQL Server DateTime or DateTime2 column. It's a follow-up of my previous article on using a TimeStamp column for that same purpose. In most -if not all- concurrency checking cases it actually makes more sense to use a DateTime column instead of a TimeStamp. The DateTime data types occupy the same storage (8 bytes) as a TimeStamp, or even less: DateTime2 with 'low' precision takes only 6 bytes. On top of that: their content makes sense to the end user. Unfortunately the DateTime data types are 'a little bit' less evident to use for concurrency checking: you need to declare a trigger (or a stored procedure) on the table, and you need to hack the entity model.

A sample table

Sample time! Let's start with creating a table to hold some data.

Table definition

Here's how the table looks like (the solution at the end of the article contains a full T-SQL script). The LastModified column will be used for optimistic concurrency checking:

CREATE TABLE [dbo].[Hero](

    [Id] [int] IDENTITY(1,1) NOT NULL,

    [Name] [nvarchar](50) NOT NULL,

    [Brand] [nvarchar](50) NULL,

    [LastModified] [datetime] NULL,

 CONSTRAINT [PK_Hero] PRIMARY KEY CLUSTERED

(

    [Id] ASC

))

Trigger definition

Unlike an Identity or a TimeStamp value, a DateTime value is not automatically generated and/or updated. So we have to give the database a little help, e.g. by creating a trigger for insert and update on that table:

CREATE TRIGGER [dbo].[trg_iu_Hero]

ON [dbo].[Hero]

AFTER INSERT, UPDATE

AS

BEGIN

   SET NOCOUNT ON;

 

   UPDATE [dbo].[Hero]

      SET LastModified = GETDATE()

    WHERE Id IN (SELECT Id FROM inserted)

END


Alternatively, you could insert through a stored procedure. 

A sample application

I already prepared for you a small sample application. Here's how the main window looks like:

Cute, isn't it ?

The problem

In the entity model, you have to make sure that the LastModified column has the correct settings (Fixed and Computed):

Run the application with just the generated code. You will observe that when you update a record, the entity's LastModified property will NOT be updated. SQL Server Profiler will reveal that only an update statement is issued. The new value of LastModified is assigned by the trigger but NOT fetched:

The solution

In order to let the Entity Framework fetch the new value of the DateTime column -or whatever column that is modified by a trigger-, you need to hack the model's XML and manually add the following attribute in the SSDL:

Somewhere in Redmond there will certainly be an architect who will provide an excuse for this behavior. To us developers, this sure smells like a bug. Anyway, if you re-run the application with the modified SSDL, the new DateTime value will appear after insert or update. SQL Server profiler reveals the extra select statement:

Source Code

Here's the source code, the whole source code, and nothing but the source code: U2UConsult.EF40.DateTimeConcurrency.Sample.zip (616,27 kb)

Enjoy!

Thank you

 

This article is dedicated to my 3-year old daughter Merel. Last week she briefly turned into a real angel, but then decided to come back.

I want to thank from the bottom of my heart everybody who helped saving her life: her mama, her mammie, the MUG, and the emergency, reanimation, intensive care, and pediatric departments of the uza hospital.

 

Self-Tracking Entities with Validation and Tracking State Change Notification

This article explains how to extend Self-Tracking Entities (STE) from Entity Framework (EF) 4.0 with validation logic and (tracking) state change notification, with just minimal impact on the T4 files. We'll build a two-tier application that submits local changes in a WPF application via a WCF service to a database table. The STE are extended with validation logic that is reusable on client and server. The client is notified when the change tracker of an entity changes its state. The tracking state is displayed to the end user as an icon. Here's the client application in action:

For more details on the foundations of building N-Tier apps with EF 4.0, please read Peter Himschoots article.

Source Code

For the fans of the source-code-first approach, here it is: U2UConsult.SelfTrackingEntities.Sample.zip (622,23 kb)

The structure of the solution is as follows:

Preparation

Database table

First you need a SQL Server table. The provided source code contains a script to generate a working copy of the SalesReason table in the AdventureWorks2008 sample database. This is its initial content:

Data Access Layer

When you have it, it's time to fire up Visual Studio.NET. Create a WCF web service project with an ADO.NET Entity Model. Add the SalesReason2 table to the model (I renamed the entity and entity set to SalesReason and SalesReasons respectively). While you're in the designer, generate the code for the ObjectContext and the Self-Tracking Entities (right click in the designer, select "Add Code Generation Item", select "ADO.NET Self-Tracking Entity Generator"). Add the canonical service methods to fetch the full list of SalesReasons, and to add, delete, and update an individual SalesReason. Here's an example (I personally like to combine Add and Update operations in a Save method):

public List<SalesReason> GetSalesReasons()

{

    using (AdventureWorks2008Entities model = new AdventureWorks2008Entities())

    {

        List<SalesReason> result = new List<SalesReason>();

        result.AddRange(model.SalesReasons);

        return result;

    }

}

 

public void DeleteSalesReason(SalesReason reason)

{

    using (AdventureWorks2008Entities model = new AdventureWorks2008Entities())

    {

        model.SalesReasons.Attach(reason);

        model.SalesReasons.DeleteObject(reason);

        model.SaveChanges();

    }

}

 

public SalesReason SaveSalesReason(SalesReason reason)

{

    using (AdventureWorks2008Entities model = new AdventureWorks2008Entities())

    {

        reason.ModifiedDate = DateTime.Now;

        if (reason.ChangeTracker.State == ObjectState.Added)

        {

            model.SalesReasons.AddObject(reason);

            model.SaveChanges();

            reason.AcceptChanges();

            return reason;

        }

        else if (reason.ChangeTracker.State == ObjectState.Modified)

        {

            model.SalesReasons.ApplyChanges(reason);

            model.SaveChanges();

            return reason;

        }

        else

        {

            return null; // or an exception

        }

    }

}

 

Self Tracking Entities

Add a new class library to the project, call it STE. Drag the Model.tt T4 template from the DAL to the STE project. Add a reference to serialization in the STE project. Add a reference to the STE in the DAL project. Everything should compile again now.

WPF Client

Add a WPF application to the solution. In this client project, add a reference to the STE, and a service reference to the DAL. Add a ListBox and some buttons, with straightforward code behind:

private void RefreshSalesReasons()

{

    this.salesReasons = this.GetSalesReasons();

 

    this.SalesReasonsListBox.ItemsSource = this.salesReasons;

}

 

private ObservableCollection<SalesReason> GetSalesReasons()

{

    using (DAL.SalesReasonServiceClient client = new DAL.SalesReasonServiceClient())

    {

        ObservableCollection<SalesReason> result = new ObservableCollection<SalesReason>();

        foreach (var item in client.GetSalesReasons())

        {

            result.Add(item);

        }

 

        return result;

    }

}

 

private void Update_Click(object sender, RoutedEventArgs e)

{

    SalesReason reason = this.SalesReasonsListBox.SelectedItem as SalesReason;

    if (reason != null)

    {

        reason.Name += " (updated)";

    }

}

 

private void Insert_Click(object sender, RoutedEventArgs e)

{

    SalesReason reason = new SalesReason()

    {

        Name = "Inserted Reason",

        ReasonType = "Promotion"

    };

    reason.MarkAsAdded();

 

    this.salesReasons.Add(reason);

 

    this.SalesReasonsListBox.ScrollIntoView(reason);

}

 

private void Delete_Click(object sender, RoutedEventArgs e)

{

    SalesReason reason = this.SalesReasonsListBox.SelectedItem as SalesReason;

    if (reason != null)

    {

        reason.MarkAsDeleted();

    }

}

 

private void Commit_Click(object sender, RoutedEventArgs e)

{

    using (DAL.SalesReasonServiceClient client = new DAL.SalesReasonServiceClient())

    {

        foreach (var item in this.salesReasons)

        {

            switch (item.ChangeTracker.State)

            {

                case ObjectState.Unchanged:

                    break;

                case ObjectState.Added:

                    client.SaveSalesReason(item);

                    break;

                case ObjectState.Modified:

                    client.SaveSalesReason(item);

                    break;

                case ObjectState.Deleted:

                    client.DeleteSalesReason(item);

                    break;

                default:

                    break;

            }

        }

 

        this.RefreshSalesReasons();

    }

}


Now you're ready to extend the STE with some extra functionality.

Validation

It's nice to have some business rules that may be checked on the client (to provide immediate feedback to the user) as well as on the server (to prevent corrupt data in the database). This can be accomplished by letting the self-tracking entities implement the IDataErrorInfo interface. This interface just contains an indexer (this[]) to validate an individual property, and an Error property that returns the validation state of the whole instance. Letting the STE implement this interface can be easily done by adding a partial class file. The following example lets the entity complain if its name gets shorter than 5 characters:

public partial class SalesReason : IDataErrorInfo

{

    public string Error

    {

        get

        {

            return this["Name"];

        }

    }

 

    public string this[string columnName]

    {

        get

        {

            if (columnName == "Name")

            {

                if (string.IsNullOrWhiteSpace(this.Name) || this.Name.Length < 5)

                {

                    return "Name should have at least 5 characters.";

                }

            }

 

            return string.Empty;

        }

    }

}


If you add a data template to the XAML with ValidatesOnDataErrors=true in the binding, then the GUI will respond immediately if a business rule is broken.

XAML:

<TextBox

   Width="180"

   Margin="0 0 10 0">

    <Binding

       Path="Name"

       Mode="TwoWay"

       UpdateSourceTrigger="PropertyChanged"

       NotifyOnSourceUpdated="True"

       NotifyOnTargetUpdated="True"

       ValidatesOnDataErrors="True"

       ValidatesOnExceptions="True"/>

</TextBox>


Result:

The same rule can also be checked on the server side, to prevent persisting invalid data in the underlying table:

public SalesReason SaveSalesReason(SalesReason reason)

{

    if (!string.IsNullOrEmpty(reason.Error))

    {

        return null; // or an exception

    }

 

    ...

 

Notification of Tracking State Change

By default, an STE's tracking state can be fetched by instance.ChangeTracker.State. This is NOT a dependency property, and its setter doesn't call PropertyChanged. Clients can hook an event handler to the ObjectStateChanging event that is raised just before the state changes (there is no ObjectStateChanged event out of the box). You're free to register even handlers in your client, but then you need to continuously keep track of which change tracker belongs to which entity: assignment, lazy loading, and (de)serialization will make this a cumbersome and error prone endeavour.

To me, it seems more logical that an entity would expose its state as a direct property, with change notification through INotifyPropertyChanged. This can be achieved -again- by adding a partial class file:

public partial class SalesReason

{

    private string trackingState;

 

    [DataMember]

    public string TrackingState

    {

        get

        {

            return this.trackingState;

        }

 

        set

        {

            if (this.trackingState != value)

            {

                this.trackingState = value;

                this.OnTrackingStateChanged();

            }

        }

    }

 

    partial void SetTrackingState(string newTrackingState)

    {

        this.TrackingState = newTrackingState;

    }

 

    protected virtual void OnTrackingStateChanged()

    {

        if (_propertyChanged != null)

        {

            _propertyChanged(this, new PropertyChangedEventArgs("TrackingState"));

        }

    }

}


The only thing you need to do now, is to make sure that the SetTrackingState method is called at the right moment. The end of the HandleObjectStateChanging looks like a nice candidate. Unfortunately this requires a modification of the code that was generated by the T4 template. For performance reasons I used a partial method for this. This is the extract from the SalesReason.cs file:

// This is a new definition

partial void SetTrackingState(string trackingState);

//

 

private void HandleObjectStateChanging(object sender, ObjectStateChangingEventArgs e)

{

    //

    this.SetTrackingState(e.NewState.ToString()); // This is a new line

    //

 

    if (e.NewState == ObjectState.Deleted)

    {

        ClearNavigationProperties();

    }

}


Just modifiying the generated code is probably not good enough: if later on you need to update your STE (e.g. after adding a column to the underlying table), the modifications will get overriden again. So you might want to modify the source code of the T4 template (search for the HandleObjectStateChanding method and adapt the source code). Fortunately this is a no-brainer: most of the T4 template is just like a C# source code file, but without IntelliSense. The rest of the file looks more like classic ASP - ugh.

Anyway, you end up with a TrackingStatus property to which you can bind user interface elements, wiith or without a converter in between. In the sample application I bound an image to the tracking state:

<Image

   Source="{Binding

       Path=TrackingState,

       Converter={StaticResource ImageConverter}}"

   Width="24" Height="24" />


Here's how it looks like:

In general, I think there are not enough partial methods defined and called in the Entity Framework T4 templates. To be frank: 'not enough' is an understatement: I didn't find a single partial method.

Optimistic concurrency using a SQL Timestamp in Entity Framework 4.0

This article explains how to implement optimistic concurrency checking in the Entity Framework 4.0, using a SQL Server Timestamp column. But you could have derived that from its title.

What is a Timestamp?

Despite its name, the SQL Server Timestamp data type has nothing to do with time. DateTime2 on the other hand, is DateTime too [sorry, I couldn't resist that]. A timestamp is just an eight-bytes binary number that indicates the relative sequence in which data modifications took place in a database. The value in a column of the type Timestamp is always provided by SQL Server: it is calculated when a row is inserted, and augmented with each update to the row, to a ever increasing value that is unique in the whole database. The Timestamp data type was initially conceived for assisting in recovery operations, and you also use it to synchronize distributed databases: based on the timestamp you can detect the order in which data was added or updated, and replay a sequence of modifications. But the most common usage of timestamp is optimistic concurrency checking: when updating a row you can compare its current timestamp with the one you fetched originally. If the values are different, you know that someone else updated the row behind your back. And you know this without holding any locks on the server while you were busy, so its a very scalable solution. This type of concurrency checking is called 'optimistic': you assume that in most cases you will be able to successfully update without the need for conflict resolution.

A sample of the geeky kind

Let's create a table with such a column (the scripts-folder in the provided solution at the end of this article contains a full script):

CREATE TABLE [dbo].[FerengiRule](

    [ID] [int] NOT NULL,

    [Text] [nvarchar](100) NOT NULL,

    [Source] [nvarchar](100) NOT NULL,

    [Timestamp] [timestamp] NOT NULL,

 CONSTRAINT [PK_FerengiRule] PRIMARY KEY CLUSTERED

(

    [ID] ASC

)


Populate it with your favorite 'Ferengi Rules of Acquisition'. You find all of these here. In a WPF solution, create an entity model, and add the table to it. You see that the timestamp column has

  • Fixed as value for the Concurrency Mode property, so the column will appear in the WHERE-clause of any insert, update, or delete query, and
  • Computed as value for the StoreGeneratedPattern property, so a new value is expected from the server after insert or update.

Next, build an application with a fancy transparent startup screen, that allows you to open multiple edit windows on the same data. The startup screen could look like this:

The mainwindow of the application contains just an editable grid on the table's contents. It allows you to

  • set the concurrency resolution mode,
  • upload local modifications to the database,
  • get the current server data, and last but not least
  • restore the table to its original contents (that's an extremely useful feature in this type of application).

Here's how the window looks like:

Visualizing a Timestamp value

Just like GUIDs and technical keys, you should avoid showing timestamp values on the user interface. This demo is an exceptional to this general rule, so I built a TimestampToDouble converter to translate the eight-byte binary number to something more readable. I don't guarantee a readable output on an old active database where the timestamp value is very high, but it works fine for a demo on a fresh database:

public class SqlTimestampToDoubleConverter: IValueConverter

{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        if (value == null)

        {

            return null;

        }

 

        byte[] bytes = value as byte[];

        double result = 0;

        double inter = 0;

        for (int i = 0; i < bytes.Length; i++)

        {

            inter = System.Convert.ToDouble(bytes[i]);

            inter = inter * Math.Pow(2, ((7 - i) * 8));

            result += inter;

        }

        return result;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        throw new NotImplementedException();

    }

}

 

Concurrency

Generated SQL Queries

If you run your SQL Profiler while modifying data through via the main window, you'll see that the Entity Framework query's WHERE-clause contains the timestamp, and that after the update the new value is fetched for you:

If there's no row to be updated, then someone else must have modified (or deleted) it. You can test that very easily with the sample application by opening multiple edit windows and playing around with the data.

Client side conflict resolution

When the entity framework discovers a concurrency violation when saving your changes, it appropriately throws an OptimisticConcurrencyException. It's then time for you to solve the conflict. In most cases, that means fetching the current values, sending these to the GUI, and let the end user decide what should happen. The data access layer code for inserts and updates will look like this:

foreach (var rule in this.rules)

{

    try

    {

        switch (rule.ChangeTracker.State)

        {

            case ObjectState.Added:

                entities.FerengiRules.AddObject(rule);

                entities.SaveChanges();

                break;

            case ObjectState.Modified:

                entities.FerengiRules.ApplyChanges(rule);

                entities.SaveChanges();

                break;

            default:

                break;

        }

    }

    catch (OptimisticConcurrencyException)

    {

        // Return Current Values

        // ...

    }

}

 

Server side conflict resolution

The Entity Framework also provides automated conflict resolution strategies that might be useful in some scenarios (although to be honest: I can't think of any). There's a Refresh method that you can use to decide whether it's the client version or the server (store) version that should be persisted when there's a conflict. Here's how the catch-block could look like:

catch (OptimisticConcurrencyException)

{

    switch (this.conflictResolution)

    {

        case ConflictResolution.Default:

            throw;

        case ConflictResolution.ServerWins:

            entities.Refresh(RefreshMode.StoreWins, rule);

            entities.SaveChanges();

            break;

        case ConflictResolution.ClientWins:

            entities.Refresh(RefreshMode.ClientWins, rule);

            entities.SaveChanges();

            break;

        default:

            break;

    }

}

 

Source Code

Oops ... almost forgot: here's the source code of the whole thing: U2UConsult.EF40.OptimisticConcurrency.Sample.zip (470,96 kb)

Enjoy!

WPF 4.0 and Windows 7: get more Functionality per Square Inch

The Windows 7 taskbar comes with nice features like a thumbnail preview with clickable thumb buttons, a progress bar in the taskbar item, and jump list items and task items in its context menu. Access to the shell integration API from the managed world is done through the System.Windows.Shell namespace that comes with .NET 4.0. This namespace decorates Window and Application with some new dependency properties, so you better make use of it.

Here's an overview of the TaskbarItemIfo object model:

The screenshot comes from a small application to demonstrate this object model. Here's how the main form looks like:

The Chart and Pie buttons switch the displayed chart type, the Recalculate button simulates a long running operation (just an excuse for showing the progress bar). Here's the alternative view:

TaskBarItemInfo

When hovering with the mouse over the taskbar item, it shows only the relevant part of the screen in its thumbnail, and operational buttons - just like in the first image above.

Everything is defined in the xaml as follows:

<Window.TaskbarItemInfo>

    <TaskbarItemInfo

       x:Name="taskBarItemInfo1"

       ThumbnailClipMargin="5 95 100 65"

       Description="Taskbar Item Info Sample">

        <TaskbarItemInfo.ThumbButtonInfos>

            <ThumbButtonInfoCollection>

                <ThumbButtonInfo

                   Click="Recalculate_Click"

                   Description="Recalculate"

                   ImageSource="/Assets/Images/refresh.png" />

                <ThumbButtonInfo

                   Click="BarChart_Click"

                   Description="Bar Chart"

                   ImageSource="/Assets/Images/chart.png" />

                <ThumbButtonInfo

                   Click="Pie_Click"

                   Description="Pie Chart"

                   ImageSource="/Assets/Images/pie.png"/>

            </ThumbButtonInfoCollection>

        </TaskbarItemInfo.ThumbButtonInfos>

    </TaskbarItemInfo>

</Window.TaskbarItemInfo>


I hooked the thumb buttons to the same click event as their counterparts on the main form, but everything also works with command bindings. In fact, the taskbar item has more FSI than the original app, that's Functionality per Square Inch.

Overlay

The taskbar icon can be decorated with an extra image to inform the user about the state of the application. This overlay image can be set in XAML (through data binding, if you want), but in a lot of cases you'll want to change the image from source code. Here's how this is done:

this.taskBarItemInfo1.Overlay = new BitmapImage(

    new Uri(

        @"..\..\Assets\Images\pie.png",

        UriKind.Relative));

 

ProgressBar

The task bar item can be decorated with a progress bar. This is how it's done from C#:

this.taskBarItemInfo1.ProgressState = TaskbarItemProgressState.Normal;

for (double d = 0; d < 80; d++)

{

    this.taskBarItemInfo1.ProgressValue = d / 100;

    Thread.Sleep(50);

}

this.taskBarItemInfo1.ProgressState = TaskbarItemProgressState.Paused;

Thread.Sleep(2000);

this.taskBarItemInfo1.ProgressState = TaskbarItemProgressState.Error;

for (double d = 80; d > 0; d--)

{

    this.taskBarItemInfo1.ProgressValue = d / 100;

    Thread.Sleep(50);

}

this.taskBarItemInfo1.ProgressState = TaskbarItemProgressState.None;


Here's the progress bar in action:

ProgressValue is a value between 0 and 1, while ProgressState is one of the following:

  • None: well - no progress bar,
  • Normal: a green bar,
  • Paused: a yellow bar,
  • Error: a red bar,
  • Indeteminate: a zigzagging green bar (very nice in combination with a wait cursor on the form)

Source Code

As always you get the full source code (VS 2010): U2UConsult.Windows7.Sample.zip (864,23 kb)

Enjoy!

Globalizing and Localizing a WPF application

This article describes how to localize a WPF application using the WPF Localization Extension project from Codeplex. On one hand, this is a fine tool. On the other hand, it's a crying shame that WPF developers need to rely on external sources for something as basic as localization. As you know, localization support is nicely integrated in Microsoft's other development stacks, like WinForms and ASP.NET. So far for the ranting, let's get to the solution.

Terminology

Globalization is making your application ready to be localized. This boils down to separating culture-specific elements (texts, images, colors, ...) from the code. The globalization code analysis rules may help you to do this.

Localization is tailoring your application toward a specific language and region by providing these culture-specific elements (e.g. in a resource file or a database).

Options for WPF localization

These are a couple of options for localizing a WPF application:

  • use the clumsy and error prone LocBaml tool. Don't get me wrong: I really like the idea of skipping the globalization step and then do localization as an afterthought. But just read the intro of this article for a list of reasons NOT to use LocBaml,
  • use classic RESX files, or
  • use WPF ResourceDictionaries.

More details about the pros and cons of these alternatives can be found here.

The WPF Localization Extension project

The WPF Localization Extension allows you to localize your application using classic .resx files. The project revolves around a custom markup extension that allows you to declaratively (in XAML) bind control properties to localized resources. The library offers a lot of functionality, but more important: it is well-written and well-documented (at least in its source code). I built a small sample application that walks through some of its features. Here's how this application looks like. You find its source code at the end of this article:

The project is decorated with the following resource files: 

Declarative Localization

The markup extension and its namespaces are registered by the following declaration on top your XAML file (you might want to change the project's source code to choose a more appropriate namespace):

xmlns:lex="http://schemas.root- project.org/xaml/presentation"


You can now set up a binding from a control's property to a resource, like this:

<TextBlock Text="{lex:LocText Key=Tomato, Dict=Translations, Assembly=U2UConsult.WPF.Localization.Sample}" />


It's possible to ignore the current culture, and force a specific culture for a binding, like this:

<TextBlock Text="{lex:LocText Key=Duck, Dict=Translations, Assembly=U2UConsult.WPF.Localization.Sample, ForceCulture=nl}" />


My sample application only fetches string resources, but WPF Localization Extension> supports the following resource types out of the box:

  • Brush,
  • Double,
  • FlowDirection,
  • Image,
  • Text, and
  • Thickness.

For other data types you'll need to plug in a Converter.

Programmatic Localization

Sometimes we need to localize a control in source code, e.g. when the control is dynamically created. In this case we can set the binding programmatically, like this:

LocTextExtension loc = new LocTextExtension("U2UConsult.WPF.Localization.Sample:Translations:Pumpkin");

loc.SetBinding(this.PumpkinTextBlock, TextBlock.TextProperty);


If data binding is not needed (or not possible), the you can fallback to a lookup in the .resx file using GetLocalizedObject, like this:

string pinguin = LocalizeDictionary.Instance.GetLocalizedObject<string>(

    "U2UConsult.WPF.Localization.Sample",

    "Translations",

    "Pinguin",

    CultureInfo.GetCultureInfo("nl-BE"));

this.PinguinTextBlock.Text = pinguin;

 

Design time support

Localization at run time is one thing, but as a developer we like to see the result without running the application. The LocalizeDictionary.DesignCulture dependency property provides a Culture for Visual Studio's designers. It can be set in XAML, as follows:

lex:LocalizeDictionary.DesignCulture="nl-BE"


[By the way: the design time support only started working on my VS2010 after I recompiled the codeplex source with VS2010.]

On top of that, the markup extension provides a DesignValue property that sets the value in Visual Studio's Designer, regardless of the (Design-)Culture. Here's a sample:

<TextBlock Text="{lex:LocText Key=Tomato, Dict=Translations, Assembly=U2UConsult.WPF.Localization.Sample, DesignValue=#Tomato#}" />


Here's how these two features look like at design time:

Finally, the markup extension also provides a InitialValue for Blend support.

Missing cultures and missing translations

I guess we all agree that our application should never totally crash if a string can not be found in a resource file, or if the user has an unexpected or unsupported locale. Here are some techniques to get around this.

Missing resources

It's not a good idea to just fallback to a default language for missing entries, without a warning to the end user. In the best case this will only create confusion. But just take a look at the following interlingual homographs and consider what would happen if they appear in the middle of a half-translated window:

  • coin is french for corner,
  • file is dutch for traffic jam, and
  • gift is german for poison

So the invariant culture should NOT be English (or whatever 'real' language), but still remain comprehensible. In my app, the invariant resource file looks like this:

When a translation (or the whole culture) falls back to the invariant culture, the user interface looks like this (Tomato and Pumpkin are not translated):

Missing cultures

If a specific culture is not found (e.g. 'fr-NL') then it makes sense to first check if the language exists ('fr'), and only use the invariant culture as a last resort. That's exactly what the following code does. The 'French' and 'Dzongkha' buttons in the sample application test all code paths:

private void SwitchCulture(string culture)

{

    CultureInfo ci = CultureInfo.InvariantCulture;

    try

    {

        ci = new CultureInfo(culture);

    }

    catch (CultureNotFoundException)

    {

        try

        {

            // Try language without region

            ci = new CultureInfo(culture.Substring(0, 2));

        }

        catch (Exception)

        {

            ci = CultureInfo.InvariantCulture;

        }

    }

    finally

    {

        LocalizeDictionary.Instance.Culture = ci;

        this.CultureTextBlock.Text = ci.EnglishName;

    }

}

 

Source code

Last but not least, here's the source code of the small sample project: U2UConsult.WPF.Localization.Sample.zip (2,41 mb)

Enjoy!