40

I currently have two text boxes which accept any number. I have a text block that takes the two numbers entered and calculates the average.

I was wondering if there was a way I could bind this text block to both text boxes and utilize a custom converter to calculate the average? I currently am catching the text changed events on both text boxes and calculating the average that way, but I am under the assumption data binding would be more efficient and easier.

4 Answers 4

54

You're looking for MultiBinding.

Your XAML will look something like this:

<TextBlock> <TextBlock.Text> <MultiBinding Converter="{StaticResource myConverter}"> <Binding Path="myFirst.Value" /> <Binding Path="mySecond.Value" /> </MultiBinding> </TextBlock.Text> </TextBlock> 

With reasonable replacements for myConverter, myFirst.Value, and mySecond.Value.

Sign up to request clarification or add additional context in comments.

2 Comments

In case I want to pass a constance value to one of the binding of multi-binding, how can I do it? Please help!
@Jacob : By mistake i hit down vote button and now it does allow me to revert it and says - "i cannot until next edit" :-(
36

Create a converter that implements IMultiValueConverter. It might look something like this:

class AverageConverter : IMultiValueConverter { #region IMultiValueConverter Members public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int total = 0; int number = 0; foreach (object o in values) { int i; bool parsed = int.TryParse(o.ToString(), out i); if (parsed) { total += i; number++; } } if (number == 0) return 0; return (total/number).ToString(); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } 

A multivalue converter receives an object array, one for each of the bindings. You can process these however you need, depending on whether you're intending it for double or int or whatever.

If the two textboxes are databound, you can use the same bindings in the multibinding for your textblock (remembering to notify when the property changes so that your average is updated), or you can get the text value by referring to the textboxes by ElementName.

<TextBox Text="{Binding Value1}" x:Name="TextBox1" /> <TextBox Text="{Binding Value2}" x:Name="TextBox2" /> <TextBlock> <TextBlock.Text> <MultiBinding Converter="{StaticResource AverageConverter}"> <Binding ElementName="TextBox1" Path="Text" /> <Binding ElementName="TextBox2" Path="Text" /> <!-- OR --> <!-- <Binding Path="Value1" /> --> <!-- <Binding Path="Value2" /> --> </MultiBinding> </TextBlock.Text> </TextBlock> 

Comments

2

Or, you could make a property in code behind, and bind the TextBlock to that ... I do that all the time, and it's a little simpler than making a converter, then doing that same code there.

Example: (in your code behind of the xaml):

public double AvgValue { get { return (valueA + valueB) / 2.0; } } 

And then, in your XAML:

<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=AvgValue}" /> 

That's a LOT simpler than a custom converter.

4 Comments

Sorry for those of you who saw this without the XAML... I forgot to space it... it's there now :)
You can also put an x:Name on your control and use that in the text binding rather than RelativeSource :)
Umm, that doesn't work. The AvgValue property (in your example) doesnt exist in the UserControl class, and changing the UserControl x:type to the TableRow (the class that I have extending the UserControl class) wont find the ancestor. So can you extend this example to a more working solution?
but using TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=AvgValue} by creating another property, consumes extra memory, say if the object collection count is massive.
0

Just to add step-by-step procedure to Timothy's answer:

  1. Setup the View.TextBlock.Text property to bind to the ViewModel.AvgValue property.
  2. Catch the TextChanged event of the TextBox control, then set the AvgValue in the handler of that TextChanged event.
  3. As part of that handler in step 2, make sure to raise a property change so that the TextBlock is updated.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.