Posted by: Zeeshan Amjad | January 15, 2010

Multi Biniding and Multi value converter


Sometimes we have to convert value depends on more than one variables. In that case we are going to use the multi value converter. Lets suppose we want to define the control template of progress bar and instead of displaying its current value, we want to display the current progress in percentage. Here is a class diagram to show the class hierarchy of binding.

BindingBase

Here is our multi value converter to do this.

  1: [ValueConversion(typeof(String), typeof(String))]
  2: public class MyProgressBarConverter : IMultiValueConverter
  3: {
  4:     public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  5:     {
  6:         double value = (double)values[0];
  7:         double min = (double)values[1];
  8:         double max = (double)values[2];
  9:         double range = max - min;
 10:         double currentPosition = value - min;
 11:         double percentage = currentPosition * 100 / range;
 12:         return String.Format("{0}%", percentage.ToString());
 13:     }
 14: 
 15:     public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
 16:     {
 17:         throw new NotImplementedException();
 18:     }
 19: }
 20: 

This converter accept three parameters in values array. The first one is the current value of progress bar, second one is minimum value of progress bar and third one is maximum value of progress bar. We pass these values in the form of Multi binding. Here is XAML code to define the multi binding.

  1: <ControlTemplate x:Key="ProgressTemplate">
  2: 	<Grid>
  3: 		<Ellipse Fill="{TemplateBinding Background}" 
  4: 			 Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}"
  5: 			 Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height}"/>
  6: 		<TextBlock Foreground="{TemplateBinding Foreground}" 
  7: 			   FontSize="32" FontWeight="Bold"
  8: 			   HorizontalAlignment="Center" VerticalAlignment="Center">
  9: 			<TextBlock.Text>
 10: 				<MultiBinding Converter="{StaticResource MyProgressBarConverterObj}">
 11: 					<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
 12: 					<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
 13: 					<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
 14: 				</MultiBinding>
 15: 			</TextBlock.Text>
 16: 		</TextBlock>
 17: 	</Grid>
 18: </ControlTemplate>
 19: 

But first we create an object of our converter. Here is a XAML code to create an object of our multi value converter.

  1: <local:MyProgressBarConverter x:Key="MyProgressBarConverterObj"/>

Now our progress bar will display the current progress in the form of percentage in blue ellipse. Here is complete XAML code of the program.

  1: <Window x:Class="WpfProgressBar.Window1"
  2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:     xmlns:local="clr-namespace:WpfProgressBar"
  5:     Title="Progress Bar" Height="300" Width="400">
  6:     <Window.Resources>
  7:         <local:MyProgressBarConverter x:Key="MyProgressBarConverterObj"/>
  8:         <ControlTemplate x:Key="ProgressTemplate">
  9:             <Grid>
 10:                 <Ellipse Fill="{TemplateBinding Background}" 
 11:                      Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}"
 12:                      Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height}"/>
 13:                 <TextBlock Foreground="{TemplateBinding Foreground}" 
 14:                        FontSize="32" FontWeight="Bold"
 15:                        HorizontalAlignment="Center" VerticalAlignment="Center">
 16:                     <TextBlock.Text>
 17:                         <MultiBinding Converter="{StaticResource MyProgressBarConverterObj}">
 18:                             <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
 19:                             <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
 20:                             <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
 21:                         </MultiBinding>
 22:                     </TextBlock.Text>
 23:                 </TextBlock>
 24:             </Grid>
 25:         </ControlTemplate>
 26:     </Window.Resources>
 27: 
 28:     <Grid Background="AliceBlue">
 29:         <Grid.RowDefinitions>
 30:             <RowDefinition/>
 31:             <RowDefinition Height="2*"/>
 32:             <RowDefinition Height="2*"/>
 33:         </Grid.RowDefinitions>
 34: 
 35:         <Grid.ColumnDefinitions>
 36:             <ColumnDefinition/>
 37:             <ColumnDefinition/>
 38:         </Grid.ColumnDefinitions>
 39: 
 40:         <TextBlock Grid.Row="0" Grid.Column="0" Margin="5" 
 41:                    VerticalAlignment="Center" Text="Enter Percentage"/>
 42:         <TextBox Grid.Row="0" Grid.Column="1" Margin="5" Name="txtPercent" VerticalAlignment="Center">
 43:         </TextBox>
 44:         <ProgressBar Margin="5" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" 
 45:                      Minimum="100" Maximum="500" Value="{Binding ElementName=txtPercent, Path=Text}"/>
 46:         <ProgressBar Margin="5" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
 47:                      Minimum="100" Maximum="500" Foreground="Yellow" Background="Blue"
 48:                      Value="{Binding ElementName=txtPercent, Path=Text}"
 49:                      Template="{StaticResource ProgressTemplate}">
 50:         </ProgressBar>
 51:     </Grid>
 52: </Window>
 53: 
 54: 

And here is complete C# code of the program.

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.Windows;
  6: using System.Windows.Controls;
  7: using System.Windows.Data;
  8: using System.Windows.Documents;
  9: using System.Windows.Input;
 10: using System.Windows.Media;
 11: using System.Windows.Media.Imaging;
 12: using System.Windows.Navigation;
 13: using System.Windows.Shapes;
 14: using System.Globalization;
 15: 
 16: namespace WpfProgressBar
 17: {
 18:     /// <summary>
 19:     /// Interaction logic for Window1.xaml
 20:     /// </summary>
 21:     public partial class Window1 : Window
 22:     {
 23:         public Window1()
 24:         {
 25:             InitializeComponent();
 26:         }
 27:     }
 28: 
 29:     [ValueConversion(typeof(String), typeof(String))]
 30:     public class MyProgressBarConverter : IMultiValueConverter
 31:     {
 32:         public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
 33:         {
 34:             double value = (double)values[0];
 35:             double min = (double)values[1];
 36:             double max = (double)values[2];
 37:             double range = max - min;
 38:             double currentPosition = value - min;
 39:             double percentage = currentPosition * 100 / range;
 40:             return String.Format("{0}%", percentage.ToString());
 41:         }
 42: 
 43:         public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
 44:         {
 45:             throw new NotImplementedException();
 46:         }
 47:     }
 48: }
 49: 

This is the output of the program.

MutiBindingOutput

Advertisements

Responses

  1. Well done! 🙂

    • Thanks.

  2. I’m interested in knowing how I can use a custom MultiValueConverter for adding sub-grouping. For instance, in your State->County->City blog-post (on multi-grouping), it is assumed that the objects contain StateName and CountyName strings, but if instead they are StateIDs and CountyIDs, you’d need to run both the StateId and the CountyId through a multi-value converter (cause you need the StateId-CountyId pair to get the CountyName.

    How would you call this, particularly as it relates to multi-grouping?

    • Hi Mark

      I have to see that how can i do this. I will post a blog entry once I will find a solution of the problem you posted in your preffered way.

      Thanks to read my blog.

  3. Is this correct for this converter?

    [ValueConversion(typeof(String), typeof(String))]

    • Thanks for point out this it should be

      [ValueConversion(typeof(double), typeof(String))]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: