Home > database >  C# WPF Binding Converter not firing if bound property is null
C# WPF Binding Converter not firing if bound property is null

Time:04-27

I'm currently facing the strange issue using WPF MVVM data binding.

The idea is to use ValueConverter that displays bound value if its not null, otherwise displays string defined in ConverterParameter.

Person class with the following properties: Name (string), Surname (string), Country (class).

Country class has the following properties: CountryName (string).

The use of a IValueConverter fails when TextBlock is bound to a Person.Country.CountryName if the Person.Country is null. The IValueConverter method Convert even not firing to check if the bound value is null or not.

At the same time IMultiValueConverter works just fine, firing every time whether Person.Country null or not null.

Ideas why it is so? Tried to search for any Microsoft articles, but found nothing.

Any help is appreciated.

Source GitHub project may be found here: https://github.com/kevintw86/WpfBindingConverterIssue.git

Binding to IValueConverter (not working properly when Person.Country==null):

<TextBlock 
          Text="{Binding Person.Country.CountryName, 
          UpdateSourceTrigger=PropertyChanged, 
          Converter={StaticResource PersonConverter}, 
          ConverterParameter=- Not set -}"
          FontSize="16"/>

PersonConverter:

public class PersonConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return parameter;

            if (value == DependencyProperty.UnsetValue)
                return parameter;

            if (string.IsNullOrWhiteSpace(value.ToString()))
                return parameter;

            return value;
        }

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

Binding to IMultiValueConverter (works fine even if Person.Country==null):

<TextBlock FontSize="16">
                <TextBlock.Text>
                        <MultiBinding Converter="{StaticResource PersonMultiConverter}"
                                  ConverterParameter="- Not set -">
                            <MultiBinding.Bindings>
                                <Binding Path="Person.Country.CountryName"
                                     UpdateSourceTrigger="PropertyChanged"/>
                            </MultiBinding.Bindings>
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>

PersonMultiConverter:

public class PersonMultiConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values == null)
                return parameter;

            if (values[0] == DependencyProperty.UnsetValue)
                return parameter;

            if (values[0] == null)
                return parameter;

            if (string.IsNullOrWhiteSpace(values[0].ToString()))
                return parameter;

            return values[0];
        }

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

Person class:

public class Person : INotifyPropertyChanged
{
    private string _Name;
    public string Name
    {
        get { return _Name; }
        set 
        { 
            _Name = value;
            OnPropertyChanged();
        }
    }

    private string _Surname;
    public string Surname
    {
        get { return _Surname; }
        set 
        { 
            _Surname = value;
            OnPropertyChanged();
        }
    }

    private Country _Country;
    public Country Country
    {
        get { return _Country; }
        set 
        {
            _Country = value;
            OnPropertyChanged();
        }
    }

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string prop = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }

    #endregion
}

Country class:

public class Country : INotifyPropertyChanged
{
    private string _CountryName;
    public string CountryName
    {
        get { return _CountryName; }
        set 
        { 
            _CountryName = value;
            OnPropertyChanged();
        }
    }

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string prop = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }

    #endregion
}

MainWindowViewModel:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public MainWindowViewModel()
    {
        this.Person = new Person
        {
            Name = "John",
            Surname = null,
            Country = null,
        };
    }

    #region Properties

    private Person _Person;
    public Person Person
    {
        get { return _Person; }
        set 
        { 
            _Person = value;
            OnPropertyChanged();
        }
    }

    #endregion

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string prop = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }

    #endregion
}

CodePudding user response:

consider using TargetNullValue and FallbackValue instead of converter:

<TextBlock 
      Text="{Binding Person.Country.CountryName, 
      TargetNullValue='- Not set -', 
      FallbackValue='- Not set -'}"
  • Related