Omer van Kloeten's .NET Zen

Programming is life, the rest is mere details

News

Note: This blog has moved to omervk.wordpress.com.

Omer van Kloeten's Facebook profile

Omer has been professionally developing applications over the past 8 years, both at the IDF’s IT corps and later at the Sela Technology Center, but has had the programming bug ever since he can remember himself.
As a senior developer at NuConomy, a leading web analytics and advertising startup, he leads a wide range of technologies for its flagship products.

Get Firefox


powered by Dapper 

.NET Resources

Articles :: CodeDom

Articles :: nGineer

Culture

Projects

Two Birds with One Stone: Introducing The MultiBindingFoldingConverter

After realizing the project I'm working on is in need of two features that do not exist in WPF - one being a missing feature, the other being a bug - I decided to take action and write something that would allow one to write code that is currently an unsupported scenario.

First, let's take a look at what we want accomplish. We have the following Window, that shows the speed we're walking at. It has three combo boxes, signifying (from left to right) the language of the form (English or Dutch), the distance measurement units (Meters or Kilometres) and the time measurement units (Seconds or Hours), along with a text box that indicates the speed we're walking (as measured in KM/H). What we would like to do is to translate this information to a single string. This is how we would have done this, if the above mentioned features were not missing:

The above illustration shows a single converter (a call to string.Format) which would receive 5 values - the format (language specific, so it has to be converted using a converter), the text for "Speed" (same as the format - must be converted to the wanted language), the speed itself (after being converted from its original value to the requested distance and time unit types) and the distance and time unit types' names (converted to the language of our choice).

However, this scenario is impossible in today's WPF, so in its stead, I have created the MultiBindingFoldingConverter, which allows you to create the above tree with the following XAML:

<MultiBinding Mode="OneWay">
    <MultiBinding.Converter>
        <f:MultiBindingFoldingConverter>
            <f:Fold Converter="{StaticResource stringFormatConverter}">
                <!-- Format -->
                <f:BindingReference Index="0"
                    Converter="{StaticResource translationConverter}"
                    ConverterParameter="Format" />
                <!-- "Speed" -->
                <f:BindingReference Index="0"
                    Converter="{StaticResource translationConverter}"
                    ConverterParameter="Speed" />
                <!-- Speed value -->
                <f:Fold
                    Converter="{StaticResource speedConverter}">
                    <!-- Speed -->
                    <f:BindingReference Index="1" />
                    <!-- Distance -->
                    <f:BindingReference Index="2" />
                    <!-- Time -->
                    <f:BindingReference Index="3" />
                </f:Fold>
                <!-- Distance -->
                <f:Fold
                    Converter="{StaticResource translationConverter}">
                    <f:BindingReference Index="0" />
                    <f:BindingReference Index="2" />
                </f:Fold>
                <!-- Time -->
                <f:Fold
                    Converter="{StaticResource translationConverter}">
                    <f:BindingReference Index="0" />
                    <f:BindingReference Index="3" />
                </f:Fold>
            </f:Fold>
        </f:MultiBindingFoldingConverter>
    </MultiBinding.Converter>
    <!-- Language -->
    <Binding ElementName="language" Path="SelectedItem" />
    <!-- Speed -->
    <Binding ElementName="speed" Path="Text" />
    <!-- Distance -->
    <Binding ElementName="distance" Path="SelectedItem" />
    <!-- Time -->
    <Binding ElementName="time" Path="SelectedItem" />
</MultiBinding>

Instead of writing the Binding elements hierarchically, you simply write the logic of the conversion hierarchy using Fold (instead of MultiBinding) and BindingReference (instead of Binding) elements.

BindingReference elements are exactly what you'd guess they were - references to individual binding tags inside the original MultiBinding, using their zero-based index. For instance, the first BindingReference receives its value from the zeroth Binding element, i.e. the language binding.
Fold elements take their child BindingReference and Fold elements and fold them into a single value, much like a MultiBinding element folds many Binding elements.
Both BindingReference and Fold elements are Evaluators, which means that they can use a value converter (IValueConverter and IMultiValueConverter respectively), along with its parameter and a culture. A Mode attribute can also be placed on them, much like one would be placed on a Binding (updating the source is not fully supported and tested, simply because I have yet to find a case in which I would need it).

An additional upside to this solution is the fact that each Binding happens only once per calculation, so in our example, rather than have 9 Binding elements along with 4 more MultiBinding elements, we only have 4 Binding elements and one MultiBinding.

The code and sample are both available on a new project I opened on CodePlex, under the DotNetZen.Presentation.Converters and Converters projects respectively. I intend to keep adding new ideas and code to that repository as I go along. There's no release, but you can browse the source code itself and download a zip file of the entire code base.

Comments

No Comments