Matthias Herrmann
Matthias Herrmann

Reputation: 2790

IValueConverter - pass parameter which is a property of my custom control

I created a .cs Class for my Custom Control which is containing the following property:

  //Property which is defining the unit of the textblock in the Ringslice
    public Units Unit
    {
        get { return (Units)GetValue(UnitProperty); }
        set { SetValue(UnitProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Unit.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty UnitProperty =
        DependencyProperty.Register("Unit", typeof(Units), typeof(RingPresenter), new PropertyMetadata(Units.Degree));

In the same class I defined Units:

     public enum Units
    {
        Percent,
        Degree,
        Time
    }

Now in the generic.xaml file I got a Textblock which text is bound to another DependencyProperty in the same .cs Control class which is called Angle- the Angle should be displayed in the correct Format, for that I'm using a ValueConverter which should return a value based on the Unit property.

My databinding is working fine, but I got Issues with the ValueConverter - the last Parameters are important!

Text="{Binding Mode=TwoWay, ElementName=ringSlice, Path=EndAngle, Converter={StaticResource DoubleDegreesToInt}, ConverterParameter={Binding RelativeSource={RelativeSource TemplatedParent}, Path=Unit}}"

Accessing the Parameter in the ValueConverter class is throwing a NullRefferenceException - here is the Code of the Value converter:

object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
    {
        Debug.WriteLine(targetType.ToString()); //returning System.String
        Debug.WriteLine(parameter.ToString());  //EXCEPTION
        return Convert.ToInt32(value);     //Is working fine without parameters        
    }

What am I doing wrong? How do I fix this Issue? Ty in regard!

Upvotes: 2

Views: 2980

Answers (2)

Fruchtzwerg
Fruchtzwerg

Reputation: 11389

Binding a ConverterParameter to a IValueConverter is not possible. A solution is to use a MultiValueConverter like described here.

The trick is to pack your information to an object and bind the properties like this:

<TextBlock>
  <TextBlock.Text>
    <MutliBinding Converter="{StaticResource myConverter}">
      <MultiBinding.Bindings>
        <Binding Path="ABC" />
        <Binding Path="DEF" />
      </MultiBinding.Bindings>
    </MultiBinding>
  </TextBlock.Text>
</TextBlock>

your MultiValueConverter uses the properties like this:

public class MyConverter: IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (double)values[0] + " " + (double)values[1];
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException("Not implemented");
    }
}

EDIT:

Because Multibinding is not possible in Universal Windows applications Damir described a way to use the Cimbalino Multibinding Behavior.

Upvotes: 3

Berin Loritsch
Berin Loritsch

Reputation: 11463

I just confirmed, and even in Universal Apps you still can't bind ConverterParameter (ref). I wouldn't be surprised if Microsoft attempted this and it turned out to be a major performance bottleneck.

There are some workarounds you can do:

  • Use MultiBinding with your custom IMultiValueConverter (but looks like that might not be possible in UWP apps?)
  • Create a value object that combines the Units enum value with the numerical portion (kind of like GridLength)
  • MVVM approach

They each have their pros and cons. The MultiBinding get invoked if any of the bound items get called. If any of the bindings changes often than this can be a performance issue to be aware of. NOTE: bindings that require you to walk the tree are expensive.

The MVVM approach is to have a ViewModel that has property that takes place of your IValueConverter completely. If the Model's Unit and Value properties change, then the ViewModel raises an INotifyPropertyChanged event for the calculated property and the UI updates.

In the container value object, you can add XAML helpers to allow you to write short cuts in string format and have it automatically parsed into the value object you want. I've used this to good effect for properties that affect placement. Binding is still an issue for individual fields.

In this case, I'd go more for the MVVM approach--even if you do it in code behind.

Upvotes: 2

Related Questions