簡體   English   中英

C# WPF 如果綁定屬性為 null,則綁定轉換器不會觸發

[英]C# WPF Binding Converter not firing if bound property is null

我目前正面臨使用 WPF MVVM 數據綁定的奇怪問題。

這個想法是使用 ValueConverter 顯示綁定值,如果它不是 null,否則顯示ConverterParameter中定義的字符串。

Person class 具有以下屬性: Name (string) , Surname (string) , Country (class)

Country class 具有以下屬性: CountryName (string)

如果Person.Country為 null,則當 TextBlock 綁定到Person.Country.CountryName時, IValueConverter的使用失敗IValueConverter方法Convert甚至不觸發以檢查綁定值是否為 null。

同時, IMultiValueConverter工作得很好,無論Person.Country null 還是 null,每次都會觸發。

想法為什么會這樣? 試圖搜索任何 Microsoft 文章,但一無所獲。

任何幫助表示贊賞。

源 GitHub 項目可以在這里找到: https://github.com/kevintw86/WpfBindingConverterIssue.git

綁定到 IValueConverter(當 Person.Country==null 時無法正常工作):

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

個人轉換器:

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();
        }
    }

綁定到 IMultiValueConverter(即使 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();
        }
    }

人 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
}

國家 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
}

主窗口視圖模型:

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
}

考慮使用TargetNullValueFallbackValue而不是轉換器:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM