Search code examples
c#wpfxamlconvertersmultibinding

WPF Multibind converter not returning value?


I have a multibind calling a converter with two bindings. For some reason it does not return anything. I put

<ItemsControl.Width>
    <MultiBinding Converter="{StaticResource ResourceKey=TimelineWidthConverter}">
        <Binding Path="AnimationManager.MaxFrame" ElementName="UC" />
        <Binding Path="AnimationManager.CurrentZoom" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type local:TimelineAnimationView}}" />
    </MultiBinding>
</ItemsControl.Width>

in the XAML file, and the converter reads:

internal class MaterialTimelineWidthConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values == null || values.Length != 2 || ReferenceEquals(values[0], DependencyProperty.UnsetValue) || ReferenceEquals(values[1], DependencyProperty.UnsetValue))
        {
            return 240;
        }

        var maxFrame = System.Convert.ToInt32(values[0]);
        var currentZoom = System.Convert.ToInt32(values[1]);

        return currentZoom*maxFrame;

    }

    public object[] ConvertBack(object values, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

The weird thing is that, if I change the XAML file to be:

<ItemsControl.Width>
    280
</ItemsControl.Width>

It works, but if I simply return 280 in the converter it just doesn't do anything. It's as if it just returns nothing but it gives no errors.

The converter worked before, when it was only a single value converter (traditional binding, no multibinding), but as soon as I added the second property and made it multi it does not work. Any tips?


Solution

  • The value returned by a multi-value converter must exactly match the type of the target property. Hence it must a return a double value, not an int.

    You will also have to do a correct conversion of the two input values. Your current code assumes that both the MaxFrame and the CurrentZoom properties of the AnimationManager class are of type int. In case they are actually doubles, change the conversion appropriately.

    public object Convert(
        object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null || values.Length != 2 ||
            ReferenceEquals(values[0], DependencyProperty.UnsetValue) ||
            ReferenceEquals(values[1], DependencyProperty.UnsetValue))
        {
            return 240d;
        }
    
        var maxFrame = System.Convert.ToInt32(values[0]); // or ToDouble
        var currentZoom = System.Convert.ToInt32(values[1]); // or ToDouble
        return (double)(currentZoom * maxFrame);
    }
    

    A probably better implementation might check if the input value are actually ints or doubles (and thus also eliminate the check for UnsetValue):

    public object Convert(
        object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double result = 240d;
    
        if (values != null && values.Length == 2 &&
            values[0] is int && values[1] is int)
        {
            var maxFrame = (int)values[0];
            var currentZoom = (int)values[1];
            result = (double)(currentZoom * maxFrame);
        }
    
        return result;
    }