Точный вопрос - почему вместо ConvertBack используется Convert, и почему действительно ConvertBack нужен здесь, в первую очередь?
Проблема
Ниже ПРИМЕР моей проблемы, я попытался упростить вещи. Это обычный WPF, никаких сторонних библиотек, сама проблема - классическая мастер-деталь с небольшим поворотом.
У меня есть список (список городов) и сетка данных (в которой перечислены все мои друзья + телефоны). Когда я выбираю список, сетка данных должна обновиться и показать ребят из выбранного города. Сетка данных выглядит следующим образом:
Name | Phone | PhoneType
Mark | 76447 | cellphone
...
Ключевой вопрос здесь - это столбец PhoneType. Каждая ячейка должна представлять собой комбинированный список, заполненный предопределенными типами телефонов (выбирается из базы данных). И поворот заключается в структуре БД. Это что-то вроде этого:
typeID | PhoneType | PhoneDescription
1 | cellphone | NULL
2 | neighbour | call only in case of emergency
В моем комбинированном ящике данных должен отображаться PhoneType НО Если присутствует PhoneDescription, его следует использовать вместо обычного PhoneType.
Конец проблемы. Вы со мной?
Осуществление
Чтобы иметь комбинированный список в сетке данных, я должен использовать столбец шаблона с комбинированным списком внутри, а не столбец комбинированного списка данных (вот почему: WPF Datagrid ComboBox DataBinding ). Итак, вот мой комбобокс:
<ComboBox ItemsSource="{Binding Path=PhoneTypesList,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Хорошо, здесь (выше) я определяю, что должно быть указано в выпадающем списке Combobox. Список записей PhoneType (в смысле базы данных).
SelectedValuePath="typeID"
SelectedValue="{Binding Path=typeID}">
Combobox должен знать о текущем значении типа телефона моего друга, поэтому здесь (выше), как я связываю эти значения - с одной стороны, я установил, что typeID из записи PhoneType должен использоваться для сопоставления, а с другой вручную я установил, что typeID из записи Friend должен быть использован. Таким образом, WPF знает, какие записи типов телефонов следует использовать в качестве текущего значения.
(Если вы не на 100% знакомы с этим переплетом, вот хорошее объяснение:
Разница между SelectedItem, SelectedValue и SelectedValuePath )
Btw. typeID используется дважды, потому что в целом я предпочитаю использовать одно и то же имя для связанных полей (полей внешнего ключа) в базе данных.
У меня есть список, у меня есть сопоставление, теперь - для отображения я не могу использовать только DisplayMemberPath, потому что мне нужно что-то более динамичное.
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource PhoneTypeConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Таким образом, чтобы отобразить PhoneType, я получаю всю запись и выбираю соответствующую строку.
[ValueConversion(typeof(PhoneTypeRecord), typeof(string))]
public class PhoneTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value == null)
return null;
var record = ((PhoneTypeRecord)value); // crash!
return record.PhoneDescription ?? record.PhoneType;
}
// we don't do any conversion back
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}
Error
Я компилирую все приложение, запускаю его, нажимаю на любой город. Работает как положено, отлично.
Тогда я нажимаю на ДРУГОЙ город. И приложение немного подумает, а затем перед обновлением списка городов или сетки данных оно аварийно завершает работу (см. Отмеченную строку выше), говоря:
Невозможно привести объект типа
'System.String' для ввода
'MyBuilderApp.PhoneTypeRecord'.
И с этим я понятия не имею, что происходит. Почему строка передается в Convert ??? Это больше похоже на ConvertBack.