Можно ли привязать к полю ValueTuple в WPF с помощью C#7

#c# #wpf #dictionary #binding #tuples

Вопрос:

Если у меня есть свойство viewmodel

 public (string Mdf, string MdfPath) MachineDefinition { get; set; }
 

и я пытаюсь привязаться к нему в XAML / WPF

 <Label Content="{Binding Path=MachineDefinition.Item2}" />
 

или

 <Label  Content="{Binding Path=MachineDefinition.MdfPath}" />
 

Я получаю ту же ошибку

введите описание изображения здесь

Я вижу, что поля ValueTuple на самом деле являются полями, а не свойствами. В этом ли проблема?

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

1. Да, в этом-то и проблема.

2. Не знаю почему, но у кортежа есть поля свойств, а у ValueTuple были поля полей. Это немного раздражает 🙁

3. Вы все еще можете сделать свойство оболочки похожим public string Mdf { get { return MachineDefinition.Mdf; } } . Это не лучший ( даже не хороший ) способ, но все равно должен сработать 🙂

4. Но это не будет поддерживать INPC из коробки. Для этого потребуется больше шаблонов. Моя первоначальная цель состояла в том, чтобы эти два свойства не создавали отдельных событий изменения. Они представляют собой согласованную пару. Мне просто нужно будет создать неизменяемый класс пары на c#. В этом случае значения не работают.

Ответ №1:

Путаница заключается в том, что для кортежа старого стиля ( до C#7 ) все элементы были свойствами

https://msdn.microsoft.com/en-us/library/dd386940(v=против 110).aspx

и, таким образом, можно связать. Для ValueTuple они являются полями

https://github.com/dotnet/runtime/blob/5ee73c3452cae931d6be99e8f6b1cd47d22d69e8/src/libraries/System.Частное.CoreLib/src/Система/Значение.cs#L269

и не поддается привязке.

Если вы прогуглите «Привязка кортежей WPF», вы получите множество ложных срабатываний, потому что старые кортежи в стиле привязываются, но новые-нет.

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

1. Похоже, что кортежи значений нарушают несколько хороших практик: они раскрывают общедоступные поля, И это означает, что они являются изменяемыми структурами, что, как я всегда думал, является серьезным недостатком. Вероятно, соображения производительности перевешивают это.

Ответ №2:

Что-то, что вы могли бы попробовать, — это реализовать преобразователь значений. Вот пример…

 public class TupleDisplayNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var tuple = value as (Int32 Id, String Name)?;

        if (tuple == null)
            return null;

        return tuple.Value.Name;
    }

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


<TextBlock Text="{Binding Converter={StaticResource TupleDisplayNameConverter}, Mode=OneWay}" />
 

Надеюсь, это поможет.

Ответ №3:

Этот MdfPath подход никогда не сработает, так как часть имени очень ограничительна с точки зрения того, где она на самом деле существует. По сути, это чистое вуду компилятора и не существует в модели типов, что означает, что все, что обращается к модели типов (включая отражение, инструменты пользовательского интерфейса, сериализаторы и т. Д.), Будет видеть только Item1 Item2 имена, а не поддельные имена.

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

1. Вы увидите в моем вопросе, что я пробовал и то, и другое. Реальная проблема заключается в том, что ValueTuple использует поля, в то время как кортеж использует свойства. Первое не поддается привязке, а второе-привязке.