Category Archives: .NET Interfaces

Introduction to Multi Binding and Multi value converter using IMultiValueConverter & MultiBinding

For Introduction to Value Converters, see the post here.

For more information on mode property, see the the post on mode here.

MultiBinding allows us to bind a binding target property to a list of source properties and then apply logic to produce a value with the given inputs. This example demonstrates how to use MultiBinding. The following example produces a TextBox that adds the numbers in TextBox1 and TextBox2 and puts the result into TextBox3. Here we have two source properties and the one target property. When you enter numbers in the TextBox1 and TextBox2 , the converter comes into play and automatically adds them and puts the result into TextBox3. The values of the Mode and UpdateSourceTrigger properties determine the functionality of the MultiBinding and are used as the default values for all the bindings in the collection unless an individual binding overrides these properties. For example, if the Mode property on the MultiBinding object is set to TwoWay, then all the bindings in the collection are considered TwoWay unless you set a different Mode value on one of the bindings explicitly.

In the following code, AddConverter implements the IMultiValueConverter interface. AddConverter takes the values from the individual bindings and stores them in the values object array. The order in which the Binding elements appear under the MultiBinding element is the order in which those values are stored in the array.

 

Figure1: Important Classes hierarchy.

Figure2: Binding classes hierarchy

The XAML for the above mentioned logic is as follows.

<Window x:Class="DataConversion.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="MainWindow" Height="350" Width="525"
        xmlns:mylocalXAMLnamespace="clr-namespace:DataConversion">
    <StackPanel>
        <StackPanel.Resources>
            <mylocalXAMLnamespace:AddConverter x:Key="XAMLResourceAddConverter" />
        </StackPanel.Resources>

        <TextBox Name="TextBox1" Text="10"></TextBox>
        <TextBox Name="TextBox2" Text="20"></TextBox>
        <Label Content="Sum of above two values:"></Label>
        <TextBox Name="textBox3">
            <TextBox.Text>
                <MultiBinding Converter="{StaticResource XAMLResourceAddConverter}">
                    <Binding ElementName="TextBox1" Path="Text"/>
                    <Binding ElementName="TextBox2" Path="Text"/>
                </MultiBinding>
            </TextBox.Text>
        </TextBox>
    </StackPanel>
</Window>

 

The MultiBinding tag takes binding as a parameter. See the following C# code that does the binding.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Markup;

namespace DataConversion
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

    }

    public class AddConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            int result = Int32.Parse((string)values[0]) + Int32.Parse((string)values[1]);
            return result.ToString();
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException("Cannot convert back");
        }
    }

}

 

You can specify multiple bindings in a MultiBinding object. When you use the MultiBinding object with a converter, it produces a final value for the binding target based on the values of those bindings. For example, color might be computed from red, blue, and green values, which can be values from the same or different binding source objects. When a value moves from the target to the sources, the target property value is translated to a set of values that are fed back into the bindings.

Download the Source Code from here

If it’s a good idea, go ahead and do it. It is much easier to apologize than it is to get permission. Admiral Grace Hopper

IValueConverter with Markup Extension

We have seen the Introduction to Value Converters in the previous post.  Converter is a Binding property of type IValueConverter. You can set this property to an instance of a class which implements that interface to intercept any movement of data from the binding source to the binding target, or vice versa. Value converters are very convenient and are used quite often.  If you want to use a normal ValueConverter in XAML, you have to add an instance of it to the resources and reference it by using a key. To learn more about instantiating an object as a resource in XAML, see the post. This is cumbersome, because and the key is typically just the name of the converter or you can derive your value converter from MarkupExtension and return its own instance in the ProvideValue override. So you can use it directly without referencing it from the resources.

public override object ProvideValue(IServiceProvider serviceProvider)
{
    throw new NotImplementedException();
}

So to enhance our experience with converters,  derive value converters from MarkupExtension. This way you can create and use it in the binding like this: Text={Binding studentname, Converter={x:MyConverter}}

Following are the steps to create a converter with Markup extension.

  1. Import namespace
    using System.Windows.Markup;

  2. Derive our class from MarkupExtension, IValueConverter
    public class ScoreToColorConverter : MarkupExtension, IValueConverter

  3. Override the ProvideValue method of MarkupExtension class and return this
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

  4. Implement the IValueConverter interface methods Convert & ConvertBack
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string s = (string) value;
        if (Int32.Parse(s) <= 35)
            return new SolidColorBrush(Colors.Red);
        else
            return new SolidColorBrush(Colors.Green);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

  5. Specify the xmlns:XXXX in the Window XAML tag
    xmlns:MyXAMLClass="clr-namespace:DataBinding_MultiConverter2"

  6. Specify the UI elements and mention the binding properties. Notice here that we are specifying the Binding converter property as Converter={MyXAMLClass:ScoreToColorConverter}, which is a simple and decent implementation.
    <TextBox Grid.Row="0" Name="TB1" Text="90"></TextBox>
     <TextBox Grid.Row="1" Name="TB2" Background="{Binding ElementName=TB1, Path=Text, Converter={MyXAMLClass:ScoreToColorConverter}}"></TextBox>

The complete XAML is:

<Window x:Class="DataBinding_MultiConverter2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="MainWindow" Height="350" Width="525"
        xmlns:MyXAMLClass="clr-namespace:DataBinding_MultiConverter2"
        >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Name="TB1" Text="90"></TextBox>
        <TextBox Grid.Row="1" Name="TB2" Background="{Binding ElementName=TB1, Path=Text, Converter={MyXAMLClass:ScoreToColorConverter}}"></TextBox>
    </Grid>
</Window>

The complete source code of the classes used is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Markup;

namespace DataBinding_MultiConverter2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class ScoreToColorConverter : MarkupExtension, IValueConverter
    {

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string s = (string) value;
            if (Int32.Parse(s) <= 35)
                return new SolidColorBrush(Colors.Red);
            else
                return new SolidColorBrush(Colors.Green);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Download the Source code from here. Default conversions may be available because of type converters that are present in the type being bound to. This behavior will depend on which type converters are available in the target. If in doubt, create your own converter.

Following are some typical scenarios where it makes sense to implement a data converter:

  • Your data should be displayed differently, depending on culture. For instance, you might want to implement a currency converter or a calendar date/time converter based on the values or standards used in a particular culture.

  • The data being used is not necessarily intended to change the text value of a property, but is instead intended to change some other value, such as the source for an image, or the color or style of the display text. Converters can be used in this instance by converting the binding of a property that might not seem to be appropriate, such as binding a text field to the Background property of a table cell.

  • More than one control or to multiple properties of controls are bound to the same data. In this case, the primary binding might just display the text, whereas other bindings handle specific display issues but still use the same binding as source information.

  • In the case of a MultiBinding, where a target property has a collection of bindings, you use a custom IMultiValueConverter to produce a final value from the values of the bindings. For example, color may be computed from red, blue, and green values, which can be values from the same or different binding source objects.

See Introduction to Value Converters in the previous post

Download the Source code from here

In organizations, real power and energy is generated through relationships. The patterns of relationships and the capacities to form them are more important than tasks, functions, roles, and positions. –Margaret Wheatley

Binding Object Properties – UpdateSourceTrigger

Download the Source Code here.

Bindings that are TwoWay or OneWayToSource listen for changes in the target property and propagate them back to the source. This is known as updating the source. For example, you may edit the text of a TextBox to change the underlying source value. As described in the mode section, the direction of the data flow is determined by the value of the Mode property of the binding. In the following sample, TextBox1 has UpdateSourceTrigger property set to PropertyChanged, so as the user starts editing the text in this control, it automatically updates the source and so the textbox2 also gets updated.

<Window x:Class="Bindingtoclasses.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        xmlns:src="clr-namespace:Bindingtoclasses"
        Title="MainWindow" Height="350" Width="525">
    <Grid DataContext="{Binding Path=EmployeeName}">
        <Grid.Resources>
                <src:Employee x:Key="myDataSource" EmployeeName="Kishore1021"/>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Text="{Binding Source={StaticResource myDataSource}, Path=EmployeeName, UpdateSourceTrigger=PropertyChanged}"/>
        <TextBox Grid.Row="1" Text="{Binding Source= {StaticResource myDataSource}, Path=EmployeeName}"></TextBox>
        <TextBox Grid.Row="2" Text="{Binding Path=.}"></TextBox>
        <TextBlock Grid.Row="3" Text="{Binding}"></TextBlock>
        </Grid>
</Window>

 

Does your source value get updated while you are editing the text or after you finish editing the text and point your mouse away from the TextBox? See the attached source code and run the exe. The UpdateSourceTrigger property of the binding determines what triggers the update of the source. The dots of the right arrows in the following figure illustrate the role of the UpdateSourceTrigger property:

If the UpdateSourceTrigger value is PropertyChanged, then the value pointed to by the right arrow of TwoWay or the OneWayToSource bindings gets updated as soon as the target property changes. However, if the UpdateSourceTrigger value is LostFocus, then that value only gets updated with the new value when the target property loses focus.

Similar to the Mode property, different dependency properties have different default UpdateSourceTrigger values. The default value for most dependency properties is PropertyChanged, while the Text property has a default value of LostFocus. This means that source updates usually happen whenever the target property changes, which is fine for CheckBoxes and other simple controls. However, for text fields, updating after every keystroke can diminish performance and it denies the user the usual opportunity to backspace and fix typing errors before committing to the new value. That is why the Text property has a default value of LostFocus instead of PropertyChanged.

 

UpdateSourceTrigger value

When the Source Value Gets Updated

Example Scenario for TextBox

LostFocus (default for TextBox.Text)

When the TextBox control loses focus

A TextBox that is associated with validation logic

PropertyChanged

As you type into the TextBox

TextBox controls in a chat room window

Explicit

When the application calls UpdateSource

TextBox controls in an editable form (updates the source values only when the user clicks the submit button)

Download the Source Code here.

"I don’t know the key to success, but the key to failure is trying to please everybody" – Bill Cosby

Introduction to Value Converters – Data Conversion

One of the nicest things that you can do with data binding in WPF is that you can convert the data as you pull it from the data source. The source data might not be compatible with what the target object property is expecting(type). so if you want to bind two properties that have incompatible types, you need some translation mechanism between your binding source and destination, that converts the value from source to target type and back. This mechanism is called ValueConverter. Basically, we will implement a value converter class, that implements the interface IValueConverter with the two methods Convert and ConvertBack. WPF already includes some value converters but in most cases you will need to write your own by implementing the IValueConverter interface.

Also, sometimes we need to apply custom logic to the Source object property data so that the data is meaningful to our bound target property. The custom logic may be in the form of a custom converter (if default type conversion does not exist). Well, to say it in simple words it is a Converter that converts value based on input as Source and provides output as Target as shown in the following figure.

image

As you can see from the above image we have both way arrows in between Source and Target. That means: the value converter not only designed to take input from the target and modify the source, it also works when source data is updated on target. As we discussed in the beginning that the Source and Target can convert each other so that’s why we have two methods defined. Convert would do conversion from Source -> Target and ConvertBack would do conversion from Target –> Source.

The following Figure1 shows the hierarchy of important classes in the Framework.

image

Figure 1: Hierarchy of important framework classes derived from Object.

image

Figure 2: Hierarchy of Binding classes

Following is the sample code to convert a (Source Property) double to an int(Target Property). Lets say I have a class that contains a double property and in my UI one of the controls is expecting an integer value. In the following example, we will bind the Slider control Value property (which is double type) to the Textbox Text property(int type;We just want to display integers). So how do we bind them together?

Implementing a IValueConverter:

Add a class to your project and call it CustomDoubletoIntegerDataConverter.Make it public and implement the IValueConverter interface. In the Convert function, value contains the Source property value and it returns the value to the Target object property. Implement the Convert function, which will be used by the Binding object, sends the source property value to the Convert function and assigns the returned value to the target property.

  1.     [ValueConversion(typeof(double), typeof(int))]
  2.     public class CustomDoubletoIntegerDataConverter : IValueConverter
  3.     {
  4.         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  5.         {
  6.             return (int) (double)value ;
  7.         }
  8.  
  9.         public object ConvertBack(object value, Type targettype, object parameter, System.Globalization.CultureInfo culture)
  10.         {
  11.             throw new NotSupportedException( "Implementation not supported" );
  12.         }
  13.  
  14.     }

Download the  Source Code from here.

The first thing you might notice is the ValueConversion attribute. This is not actually required(optional), but it helps tell developer tools what type is going to be converted to what other type. The value, targetType, and culture are all automatically passed in by WPF’s binding engine. The parameter is an optional object.

Using a ValueConverter in XAML:

First thing you need to do is to map the namespace of your converter to a XAML namespace. Then you can create an instance of a value converter in the resources of the view and give it a name. Then you can reference it by using {StaticResource}

<Window x:Class="DataConversion.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="MainWindow" Height="350" Width="525"
        xmlns:mylocalXAMLnamespace="clr-namespace:DataConversion">
    <StackPanel>
        <StackPanel.Resources>
            <mylocalXAMLnamespace:CustomDoubletoIntegerDataConverter x:Key="XAML_Instanceof_CustomDoubletoIntegerDataConverter_Class"></mylocalXAMLnamespace:CustomDoubletoIntegerDataConverter>
        </StackPanel.Resources>
        <Slider Name="Slider1"> </Slider>
        <TextBlock Name="TextBlock1" Text="{Binding ElementName=Slider1, Path=Value, Converter={StaticResource XAML_Instanceof_CustomDoubletoIntegerDataConverter_Class}}"></TextBlock>
    </StackPanel>
</Window>

 

Following is the output of binding without and with Value Converters.image

When you get the error "No constructor for type ‘…’ has 0 parameters.", you need to add an default constructor to your converter, even it’s not needed. Just for the WPF designer.

you can derive your value converter from MarkupExtension and return its own instance (this) in the ProvideValue override. So you can use it directly without referencing it from the resources, which we will see in another post.

We will also discuss amount Multi Binding and Multi Value converters in the another post.

Download the  Source Code from here.

"Let your life mean something. Become an inspiration to others so that they may try to do more and to become more than they are today." – Thomas D. Willhite