Sunday, December 1, 2013

WPF MultiBinding Example (MultiValueConverter)

As you probably know the main key of WPF is binding. We bind WPF control to a property and data flows from business logic to UI and vice versa. But what if we need to bind several properties to a single control and depending on the state of these properties we will decide what to display? This technique called MultiBinding.
MultiBinding in WPF is always accompanied with MultiValueConverter. Inside it we define the logic that will decide what value to pass to our WPF control.

Today I'll show a simple example of MultiBinding in WPF. In my sample application I have three TextBox controls and a single TextBlock. I want to achieve this scenario: I want to show the text in the TextBlock, but only if each of three TextBoxes contain some text.

WPF MultiBinding Sample Application

First, take a look at our XAML:
<Window x:Class="WPF_MultiBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="CodeArsenal.net"
        Height="158" Width="245"
        xmlns:local="clr-namespace:WPF_MultiBinding">
    <Window.Resources>
        <local:MultiValueConverter x:Key="MultiValueConverter" />
    </Window.Resources>
    
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="65" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="10" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <TextBox Name="textBoxOne" Grid.Row="0" Height="20" MaxLength="8" Grid.Column="1"
                 Text="{Binding TextOne, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        
        <TextBox Name="textBoxTwo" Grid.Row="1" Height="20" MaxLength="8" Grid.Column="1" 
                 Text="{Binding TextTwo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        
        <TextBox Name="textBoxThree" Grid.Row="2" Height="20" MaxLength="8" Grid.Column="1"
                 Text="{Binding TextThree, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBlock Name="textBlockOutput" Grid.Row="4" Grid.Column="2">
            <TextBlock.Text>
                <MultiBinding Converter="{StaticResource MultiValueConverter}">
                    <Binding Path="TextOne" />
                    <Binding Path="TextTwo" />
                    <Binding Path="TextThree" />
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </Grid>
</Window>
Did you notice that we bind three properties and define Converter for the TextBlock? By the way here is our ViewModel:
public class ViewModel : INotifyPropertyChanged
{
    public ViewModel() { }

    public event PropertyChangedEventHandler PropertyChanged;
    private string _textOne;
    public string TextOne 
    {
        get { return _textOne; } 
        set
        {
            _textOne = value;
            NotifyPropertyChanged("TextOne");
        } 
    }

    private string _textTwo;
    public string TextTwo
    {
        get { return _textTwo; }
        set
        {
            _textTwo = value;
            NotifyPropertyChanged("TextTwo");
        } 
    }

    private string _textThree;
    public string TextThree
    {
        get { return _textThree; }
        set
        {
            _textThree = value;
            NotifyPropertyChanged("TextThree");
        } 
    }

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
As you can see nothing special here. Just three properties for our TextBoxes. The real key feature of MultiBinding is Converter. We must implement IMultiValueConverter interface that allows us to apply our custom logic. The logic is pretty simple - I combine all the text that comes from TextBoxes, but only when all three of them contain text.
public class MultiValueConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        string one = values[0] as string;
        string two = values[1] as string;
        string three = values[2] as string;
        if(!string.IsNullOrEmpty(one) && !string.IsNullOrEmpty(two) && !string.IsNullOrEmpty(three))
        {
            return one + two + three;
        }
        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Enjoy! Download the source code (Visual Studio 2013 project).

7 comments:

  1. I had a problem with this one:






    It didn't want to work (to show the result) until I changed it into:





    ReplyDelete
  2. Good Tutorial...thank you...

    ReplyDelete
  3. Easy Explanation..Thanks

    ReplyDelete
  4. Nice Explanation! Very clear.

    Thank you very much

    ReplyDelete