Posts Tagged ‘Sticky Behaviour’

Switching the Keyboard to Different Languages

November 21, 2009 1 comment

Handling different languages with different keyboard layouts within the same document has only recently become a common feature in text processing applications. However, since I frequently have to work with data in different languages, I wouldn’t like to miss this ability.

In WPF, the class responsible for managing different keyboard languages is called InputLanguageManager. It exposes an attached property, InputLanguage, that accepts a culture identifier and switches the keyboard to the defined layout for this language, if one is installed. Unfortunately, this only works when the control receives focus. So, if you are typing something in a TextBox and change the InputLanguage while you are typing, e.g. through a keyboard shortcut, this change doesn’t become active unless the keyboard focus leaves the TextBox and returns again.

Also, in principle you can define different languages for paragraphs in a RichTextBox by setting the InputLanguageManager.InputLanguage on the Paragraph elements in the RichTextBoxes FlowDocument, but the keyboard doesn’t automatically change to the appropriate layout when the selection enters a section in a different language. This feature is extremely useful, so I decided to create a Sticky Property which allows to change the keyboard language effective immediately, and a Sticky Behaviour that sets the current input language according to what is set in this attached property on the FrameworkContentElements inside a RichTextBox’s FlowDocument.

Changing the Keyboard Language at Runtime

The way the KeyboardLanguage property is implemented is a typical example for the Sticky Property design pattern. A Sticky Property is an attached property that has an OnPropertyChanged handler which does some useful work, so that the property has an effect aside from storing data with the object it is set on. In the case of the KeyboardLanguage property, this work would be looking up the available keyboard languages, checking whether one of them fits the value, and activating this keyboard layout.

Public Shared ReadOnly KeyboardLanguageProperty As DependencyProperty = DependencyProperty.RegisterAttached("KeyboardLanguage", GetType(String), GetType(Localization), New FrameworkPropertyMetadata(Nothing, System.Windows.FrameworkPropertyMetadataOptions.Inherits, AddressOf OnKeyboardLanguageChanged))
Public Shared Function GetKeyboardLanguage(ByVal d As DependencyObject) As String
    Return d.GetValue(KeyboardLanguageProperty)
End Function
Public Shared Sub SetKeyboardLanguage(ByVal d As DependencyObject, ByVal value As String)
    d.SetValue(KeyboardLanguageProperty, value)
End Sub
Public Shared Sub OnKeyboardLanguageChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
    If TypeOf d Is FrameworkElement Then
        Dim l As System.Globalization.CultureInfo = FindKeyboardLanguage(e.NewValue)
        If String.IsNullOrEmpty(e.NewValue) Or l Is System.Globalization.CultureInfo.InvariantCulture Then
            d.SetValue(InputLanguageManager.InputLanguageProperty, l)
            d.SetValue(InputLanguageManager.RestoreInputLanguageProperty, True)
            InputLanguageManager.Current.CurrentInputLanguage = l
        End If
    End If
End Sub

Public Shared Function FindKeyboardLanguage(ByVal tag As String) As System.Globalization.CultureInfo
    Dim result As System.Globalization.CultureInfo = System.Globalization.CultureInfo.InvariantCulture
    If Not String.IsNullOrEmpty(tag) Then
        For Each c As System.Globalization.CultureInfo In InputLanguageManager.Current.AvailableInputLanguages
            If c.IetfLanguageTag.ToUpper.StartsWith(tag.ToUpper) Then
                result = c
            End If
            If c.IetfLanguageTag.ToUpper = tag.ToUpper Then
                Exit For
            End If
    End If
    Return result
End Function


This gives the added flexibility of supporting language-only IETF tags, so that you don’t have to know exactly which flavour of the language the target system supports.

Keeping Track of Different Languages in a FlowDocument

This is done through a sticky (or attached) behaviour. A Sticky Behaviour is an attached property that registers event handlers on the control it is attached to. In this case, the behaviour will be specialized for RichTextBoxes, because their ability to edit FlowDocuments is the most convenient way to edit structured documents in WPF.

The Sticky Behaviour is activated by setting the TracksKeyboardLanguage property to true. Whenever the selection changes, this will cause the RichTextBox to check whether there are KeyboardLanguage attributes on the parent element of the current selection, and to activate the appropriate keyboard layout:

Public Shared ReadOnly TracksKeyboardLanguageProperty As DependencyProperty = DependencyProperty.RegisterAttached("TracksKeyboardLanguage", GetType(Boolean), GetType(Localization), New PropertyMetadata(AddressOf OnTracksKeyboardLanguageChanged))
Public Shared Function GetTracksKeyboardLanguage(ByVal d As DependencyObject) As Boolean
    Return d.GetValue(TracksKeyboardLanguageProperty)
End Function
Public Shared Sub SetTracksKeyboardLanguage(ByVal d As DependencyObject, ByVal value As Boolean)
    d.SetValue(TracksKeyboardLanguageProperty, value)
End Sub
Private Shared Sub OnTracksKeyboardLanguageChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
    If TypeOf d Is RichTextBox Then
        Dim b As RichTextBox = d
        If CBool(e.OldValue) Then
            RemoveHandler b.SelectionChanged, AddressOf OnSelectionChanged
        End If
        If CBool(e.NewValue) Then
            AddHandler b.SelectionChanged, AddressOf OnSelectionChanged
        End If
    End If
End Sub

Private Shared Sub OnSelectionChanged(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim b As RichTextBox = sender
    Dim f As FrameworkContentElement = TryCast(b.Selection.Start.Parent, FrameworkContentElement)
    If f IsNot Nothing Then
        Dim tag As String = GetKeyboardLanguage(f)
        If Not String.IsNullOrEmpty(tag) Then
            If Not InputLanguageManager.Current.CurrentInputLanguage.IetfLanguageTag.ToUpper.StartsWith(tag.ToUpper) Then
                InputLanguageManager.Current.CurrentInputLanguage = FindKeyboardLanguage(tag)
            End If
        End If
    End If
    e.Handled = False
End Sub


It is always wise to make these event handlers static, so that they don’t create any references which could keep the control from being freed. Setting e.Handled to false makes sure that the RichTextBox still can accept other handlers for the SelectionChanged event.

Downloading the Example

The WPFGluePublished solution on the Downloads page contains a project called KeyboardLanguageExample which demonstrates the use of the KeyboardLanguage and TracksKeyboardLanguage properties. This example assumes that you have German, Arabic and English installed as Input languages on your computer. If you don’t have any additional keyboards installed, you can do so using the Regional and Language Options control panel in Windows.

New Sticky Star Award: Selectors and attached behaviours

November 14, 2009 Leave a comment

I just awarded 5 Sticky Stars to Zoodazzle, a user in the MSDN WPF forum who published a way of making one item only selected across a group of selector controls in a WPF form. He uses an attached (or sticky) behaviour for this and can have several groups of selectors on the same page… really elegant solution.

Look at this thread: Selectors and attached behaviours.5StickyStars


See the Sticky Star Awardees page for more links to great solutions out there.

Categories: Uncategorized Tags:

WPFGlue Patterns

November 5, 2009 4 comments

Let’s recapitulate the design requirements for WPFGlue components:

  • You shall not duplicate functionality that is already in the WPF framework.
  • You shall not mess with WPF’s correct function, like keeping objects from being freed and the like evil practices.
  • You shall not require code behind.
  • You shall not demand sub-classing controls.
  • You shall not demand interface implementations from your business objects (unless the interfaces are part of WPF itself), nor common base classes, nor any other construct that commits the developer to a strong coupling between your glue and his code.

The following design patterns have proved suitable for development under these constraints:

Sticky Properties (a.k.a. Attached Properties)

Attached properties can be used to extend the state of any element in WPF. They can be used in XAML, and neither the framework-supplied controls nor the business object model need to know them. So, they are suitable for WPFGlue.

Built-in examples for attached properties are the Canvas.Left and Canvas.Top properties, which the WPF Canvas uses to store the positions of its child elements.

Sticky Behaviours (a.k.a. Attached Behaviours)

Attached behaviours are a special kind of attached properties that register event handlers on the elements they are attached to. The event handlers provide additional functionality to the elements which is triggered through the elements standard events, while the implementation of the event handlers is contained in the class that defines the attached property.

A built-in example for a sticky behaviour is the SpellCheck.IsEnabled property, which adds the functionality of spell checking to controls based on TextBoxBase.

Josh Smith writes about attached behaviours in this article; Attached behaviours are introduced and defined by Nikhil Kothari here.

Sticky CommandBindings

Work like sticky behaviours, with the difference that they don’t handle events, but standard routed commands. Attaching a sticky CommandBinding to a WPF FrameworkElement means that this element will be able to handle the command, without having to change the original implementation of the element. A sticky CommandBinding should add / remove the CommandBindings when the value of an attached property changes.

Pete O’Hanlon gives an almost perfect example of this pattern here. Almost perfect because he uses a class CommandBinding instead of the CommandBindings collection, but this might be justified on his case since he expects the command to be used by many elements per page.

Sticky ViewModels (a.k.a. Mini-ViewModels)

Sticky ViewModels are ViewModels that don’t wrap a business object, but attach themselves to it and expose a specialized, reusable bit of functionality through their own properties and commands. Typically, a sticky ViewModel wouldn’t be the DataContext of a FrameworkElement, but it would be attached to the element as a sticky property and use the FrameworkElement’s DataContext to find the model it is supposed to work on. Controls inside the scope of the FrameworkElement would then bind to properties of the sticky ViewModel in order to benefit from it.

Quite often jobs like this are done through converters (Converters are classes that implement the IValueConverter interface). However, I view this as converter abuse. A converter is not intended for anything but type conversions, translating data between different data types and string presentations. If the intention of the solution is rather to achieve some more complex interaction between the View and the Model, I’d recommend a sticky ViewModel instead. Usually these cases are discovered by feeling the need to pass more information into the conversion routines than is readily available…

While Mini-ViewModel seems to imply that the functionality of such a class would normally be quite limited, I could imagine whole page ViewModels using this technique.

Colin Eberhardt describes the Mini-ViewModel pattern here and gives a nice example.


A ViewModelKit would be a class or set of related classes that can be instantiated and configured as XAML resources, and then be used as ViewModels through referencing the resource.

A built-in example for a ViewModelKit would be the CollectionViewSource class, which can be used to configure views of business object collections.

Sticky Markup (a.k.a. Custom Markup Extensions)

Custom markup extensions are classes derived from System.Windows.Markup.MarkupExtension, which can be used in XAML attributes using the markup extension syntax, like {Binding value}. Writing custom markup extensions is not documented very well in the WPF documentation, and I use them sparingly. They need to be initialized in place, i.e. where they are used in XAML. This limits their “stickiness” to situations where the information they need to do their job is either very simple or can be discovered from the built-in application framework. For example, I found them useful for accessing localized resources, application settings, or the current UI language.