Как правильно использовать явно реализованное свойство интерфейса и видимость wpf?

У меня следующая ситуация:

У меня есть несколько объектов ViewModel, некоторые из которых реализуют интерфейс ISomeInterfaceнекоторые не делают. Интерфейсы предоставляют свойство под названием SomeEnumeration (IEnumerable<T>).

Например:

public sealed class ViewModelA : ViewModelBase, ISomeInterface
{
    // ...

    IEnumerable<Foo> ISomeInterface.SomeEnumeration
    {
        get { ...; }
    }
}

public sealed class ViewModelB : ViewModelBase
{
    // ...
}

Мой XAML до сих пор был спроектирован таким образом, что обе модели ViewModel имеют свойства, с которыми я связываюсь (т.е. PropertyA, PropertyB, так далее.). Я еще не сталкивался с ситуацией, когда свойство, с которым я связываюсь, не существует в моделях представления, которые я устанавливаю как DataContext, Но теперь я буду... и это будет против свойства, которое явно реализовано (я не уверен, имеет ли это какое-то значение в механизме связывания WPF).

По сути, мой xaml будет выглядеть следующим образом:

<StackPanel
  Visiblity="{Binding Path=SomeEnumeration, Converter={StaticResource AnyConverter}">
    ...
</StackPanel>

Я не уверен, что это сработает, потому что:

  1. Не каждый DataContext будет содержать свойство (в противном случае оно должно быть скрыто) ... Что мне делать в этом случае?
  2. Для DataContexts, которые содержат свойство, оно явно реализовано... вы должны сначала привести в действие что ли?

2 ответа

Решение

Как правило, когда вы хотите использовать механизм привязки данных WPF, вы также должны использовать FallbackValue и TargetNullValue обязательные свойства. Что именно они делают?

FallbackValue: получает или задает значение, когда привязка не может вернуть значение.
TargetNullValue: получает или задает значение, которое используется в цели, когда значение источника равно нулю.

Джон очень хорошо объясняет механизм привязки в этом ответе:

Binding.DoNothing - это экземпляр объекта, который вы активно возвращаете из преобразователя значений; он указывает механизму привязки вообще не обновлять значение целевого свойства. Вот хороший пример Джоша Смита, для чего вы можете использовать это.

FallbackValue - это свойство, которое вы устанавливаете для привязок; это позволяет вам указать значение, которое будет применено к целевому свойству, если:

  • источник привязки не может быть разрешен (например, неверный путь привязки), или
  • значение свойства привязки равно DependencyProperty.UnsetValue или
  • преобразователь значения, используемый для привязки, генерирует исключение, или
  • конвертер значений, используемый для привязки, возвращает DependencyProperty.UnsetValue или
  • значение, созданное конвейером привязки, недопустимо для целевого свойства (например, неправильный тип)

TargetNullValue также является свойством, которое вы устанавливаете для привязок; это позволяет вам указать значение, которое будет применено к целевому свойству, если значение исходного свойства равно нулю. Например, если вы связываете текстовое поле со строковым свойством, TargetNullValue позволяет вам выбрать то, что появляется в текстовом поле, если исходная строка равна нулю.


Что касается привязки к "явно реализованному интерфейсу", реальный вопрос должен заключаться в том, как задать путь к свойству интерфейса, потому что способ реализации этого интерфейса не имеет значения. На самом деле это довольно легко сделать в XAML, и вот пример:

<TextBox Text="{Binding Path=(local:ISomeInterface.SomeProperty)}" />

Итак, чтобы ответить на ваши вопросы напрямую:

  1. использовать FallbackValue (и опционально TargetNullValue если необходимо). Например, передайте значение null, если значение привязки не может быть разрешено из-за ошибки привязки.
  2. Используйте правильный шаблон для привязки свойства Path к свойству интерфейса (см. Пример выше).

Использование XAML:

<StackPanel Visiblity="{Binding Path=(local:ISomeInterface.SomeEnumeration),
                                Converter={StaticResource AnyConverter},
                                FallbackValue={x:Null}}">
    ...
</StackPanel>

И последнее замечание: если привязка завершается неудачно рано, значение NULL FallbackValue не будет значением, передаваемым в преобразователь, это будет конечное значение, используемое независимо от того, будет ли сбой привязки на уровне свойств, на уровне преобразователя и т. д. Поэтому не ожидайте, что преобразователь все равно будет работать, передавая ему значение null.

Быстрое и хорошее решение для вашей ситуации - поместить всю вашу логику в уже установленный конвертер.

xaml: (твоя привязка)

 <StackPanel
       Visiblity="{Binding Path=., Converter={StaticResource AnyConverter}">
       ...
 </StackPanel>

CS: (ваш конвертер)

  Convert()
  {
       return value Is ISomeInterface ? 
              (((ISomeInterface)value).SomeEnumeration == SomeEnumeration.SomeValue ? 
              Visibility.Visible :  Visibility.Collapsed) : Visibility.Collapsed;       
  }
Другие вопросы по тегам