Как создать сложное свойство класса, которое можно привязать к текстовому блоку WPF?

#c# #wpf

Вопрос:

У меня есть класс со сложными свойствами, которые привязаны к моим элементам управления пользовательского интерфейса. Класс может быть преобразован по желанию в строку и из нее. Как я могу правильно привязать этот класс к текстовому полю?

 [TypeConverter(typeof(LatLongTypeConverter))]
public class LatLong : IComparable, IXmlSerializable
{
  .
  .
  .

  public override string ToString() {...}

  public static implicit operator LatLong(string L) {...}

  public static explicit operator string(LatLong L) {...}

  public class LatLongTypeConverter : TypeConverter
  {
    .
    .
    .
  }
}

public class City : INotifyPropertyChanged
{
  private string _Name = "Chicago";
  private LatLong _Location = "41.52N 87.37W";

  public string Name
  {
    get => _Name;
    set { _Name = value; Notify(); }
  }

  public LatLong Location
  {
    get => _Location;
    set { _Location = value; Notify(); }
  }

  public event PropertyChangedEventHandler PropertyChanged;
  public void Notify([System.Runtime.CompilerServices.CallerMemberName] string PropertyName = null)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }
}
 

XAML:

 <TextBlock Text="{Binding Location}"/>
 

Как заставить текстовый блок отображать «41.52 N 87.37 Вт» без использования преобразователя Ivaluecon? В настоящее время преобразование типов отлично работает в коде, но при привязке оно просто отображает пустое поле.

Комментарии:

1. В XAML преобразователь типов вызывается (процессором XAML) только тогда, когда вы сопоставляете строку с нестроковым свойством-в вашем случае LatLong. Затем обработчик XAML будет использовать конвертер для преобразования строки в экземпляр LatLong. Но поскольку вы напрямую привязываетесь к экземпляру LatLong, вам необходимо использовать преобразователь ivaluecon или добавить свойство LatLong.displayValue типа string к вашему типу (и использовать его в качестве источника привязки). Расширение разметки привязки не знает, как преобразовать экземпляр LatLong в экземпляр строки. Вы должны позаботиться об этом.

Ответ №1:

WPF нужен только TextBlock текст для привязки к строке, для чего-либо более сложного, чем это, требуется прямая привязка конвертера. Что оставляет два варианта: создайте экземпляр IValueConverter , который берет LatLong экземпляр и возвращает строку, например, вызывая ее неявное преобразование, или сделайте это в своем коде за/viewmodel/сервер, к которому вы привязываетесь.

Здесь я покажу очень простой способ сделать второй вариант, добавив дополнительное свойство для привязки WPF к:

 //New property for WPF to bind to, simply takes the full object and uses it's implicit string conversion
public string LocationString => (string)this.Location;

public LatLong Location
{
    get => _Location;
    //Here we notify changes of both properties, as one is calculated from the other
    set { _Location = value; Notify(); Notify("LocationString"); }
}
 

Затем просто измените привязку к новому свойству в XAML:

 <TextBlock Text="{Binding LocationString}"/>
 

Комментарии:

1. Вам следует подумать о том, чтобы добавить свойство LocationString в тип LatLong (как свойство только для чтения, например, с набором частных свойств (). Это делает тип LatLong более удобным для (повторного)использования.