Search code examples
c#xamlxamarin.formsmultibinding

MultiBinding in Xamarin Forms: element is null


I'm trying to use MultiBinding with Xamarin.Forms 4.8, and I can't get it to work. I have this very simple converter:

public class QuantityLabelConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return "Hello World";
    }

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

And I'm trying to use it in an XAML label, like this:

<Label>
    <Label.Text>
        <MultiBinding Converter="{StaticResource QuantityLabelConverter}">
            <Binding Path="SelectedQuantity" />
            <Binding Path="OutstandingQuantity" />
        </MultiBinding>
    </Label.Text>
</Label>

Now, when I debug, I can see that the converter is called three times: one with two null values, then another one when the SelectedQuantity value is set, and a last time when OutstandingQuantity value is assigned. So the link between the bindings and the converter seems to be working fine.

However, the page crashes and I get a "Value cannot be null.\nParameter name: element" System.ArgumentNullException.

If I replace the previous XAML with a simple

<Label Text="Hello World">

The page shows without problems, so there is something wrong with how the MultiBinding is set, but I don't know what...


Solution

  • You need to return BindableProperty.UnsetValue to use the binding FallbackValue .

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            foreach (var value in values)
            {
                if (!(value is string b))
                {
                    return "xxx";
                    // set a default value when unset
                }
    
            }
    
            string str1 = values[0].ToString();
            string str2 = values[1].ToString();
    
            return str1+str2;
        }
    

    ##Update

    I had tested the sample and found out the cause

    If you want to binding the property of ViewModel . You need to implement the interface INotifyPropertyChanged of the property instead of BindableObject .

    public class MainViewModel : INotifyPropertyChanged
    {
    
    
    
        string _name="";
        string _surname="";
    
        public string Name
        {
            get { return _name; }
            set
            {
                if(_name!=value)
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
        }
    
        public string Surname
        {
            get { return _surname; }
            set
            {
                if(_surname!=value)
                {
                    _surname = value;
                    OnPropertyChanged("Surname");
                }
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    public class NameConverter : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                foreach (var value in values)
                {
                    if (!(value is string b))
                    {
                        return " ";
                        // set a default value when unset
                    }
    
                }
    
                string str1 = values[0].ToString();
                string str2 = values[1].ToString();
    
                return str1 + str2;
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    

    enter image description here