#wpf #data-binding
Вопрос:
У меня есть представление списка в WPF, привязанное к базовой таблице, которую я извлекаю из базы данных. Код для представления списка выглядит следующим образом:
<ListView Canvas.Left="402" Canvas.Top="480" Height="78" ItemsSource="{Binding}" Name="lsvViewEditCardPrint" Width="419">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=IdCst}">Set</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=Language}">Language</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=Number}">Number</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=IdArt}">Artwork</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Столбец IdCst является внешним ключом для отдельной таблицы, и я хотел бы отобразить поле фактического имени из этой таблицы, а не только идентификатор. Кто-нибудь знает, как установить привязку данных, или есть ли событие, такое как OnItemDataBound, которое я мог бы перехватить, чтобы изменить отображение?
Ответ №1:
Это сообщение в блоге может помочь:
…Я предположил, что внешний ключ должен быть привязан к свойству ‘SelectedValue’, и есть источник элементов, который я могу привязать к своей таблице фактов, чтобы раскрывающийся список был заполнен.
В этот момент мой выпадающий список работал, но в выпадающем списке ничего не появлялось. Я, наконец, заметил свойство ‘SelectedItemPath’ — я предположил, что это будет имя поля в моем раскрывающемся списке, которое было связано с моим внешним ключом. Конечно же, это именно то, что нужно.
Ответ №2:
Я бы добавил новое свойство в ваш базовый класс:
Public ReadOnly Property NameCst() as String
Get
Return Names.LookupName(Me.IdCst)
End Get
End Property
или что-то подобное. Обратите внимание, что вам, вероятно, придется включить событие Уведомления об изменении свойства в свой .Установщик IdCst для «NameCst».
Альтернативой является написание преобразователя значений, который выполняет поиск, но это довольно тяжелый вес для чего-то настолько простого.
Ответ №3:
БУ ДА!!!
Я просмотрел образцы здесь, откопал несколько ссылок из других постов здесь и нашел ответ… IValueConverter … интерфейс, который можно использовать с WPF, который преобразует значения в точке привязки. Сначала это немного сложно собрать воедино, но не так уж сложно.
Первым шагом является создание простого класса поиска или конвертера, реализующего интерфейс IValueConverter. Для моего решения я сделал это:
Namespace TCRConverters
Public Class SetIdToNameConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
Dim taCardSet As New TCRTableAdapters.CardSetTableAdapter
Return taCardSet.GetDataById(DirectCast(value, Integer)).Item(0).Name
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
Return Nothing
End Function
End Class
End Namespace
Примечание: Я не использую метод обратного преобразования, но это требуется интерфейсом.
Оттуда вам нужно добавить ссылку на пространство имен в раздел заголовка XAML:
<Window x:Class="Main" Loaded="Main_Loaded"
// Standard references here...
xmlns:c="clr-namespace:TCR_Editor.TCRConverters"
Title="TCR Editor" Height="728" Width="1135" Name="Main">
Затем в ваших окнах.Раздел ресурсов, вы можете ссылаться на конвертер, и в моем случае я создал статическую ссылку на источник CollectionViewSource, в котором будут храниться данные:
<Window.Resources>
<CollectionViewSource Source="{Binding Source={x:Static Application.Current}, Path=CardDetails}" x:Key="CardDetails">
</CollectionViewSource>
<c:SetIdToNameConverter x:Key="SetConverter"/>
</Window.Resources>
Затем, наконец, в представлении списка, которое было частью первоначальной проблемы, вы добавляете ссылку на конвертер:
<ListView Canvas.Left="402" Canvas.Top="480" Height="78" ItemsSource="{Binding}" Name="lsvViewEditCardPrint" Width="419">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=IdCst, Converter={StaticResource SetConverter}}">Set</GridViewColumn>
// Other Columns here...
</GridView>
</ListView.View>
</ListView>
Итак, самое интересное сейчас заключается в том, что когда я запускаю событие с идентификатором карты, все, что мне нужно сделать, это сбросить настройки CollectionViewSource…
DirectCast(Me.FindResource("CardDetails"), CollectionViewSource).Source = taCardDetails.GetDataById(CardId)
…и все связующие элементы WPF делают все остальное!
Самое приятное в том, что я могу легко создавать другие конвертеры, добавлять их в различные таблицы данных или столбцы в других местах приложения, и как только я получу все данные в само приложение WPF, преобразования можно будет выполнять без обращения к базе данных.
Комментарии:
1. Краткое примечание. Я обнаружил, что компиляция класса конвертера перед добавлением всего кода XAML, по-видимому, помогает устранить некоторые «придирки», которые он вам даст, пока все не будет скомпилировано вместе.
2. Извините, что лопнул ваш пузырь, но этот конвертер попадет в базу данных по крайней мере один раз для каждой строки.
3. Истинная правда. Однако в настоящее время это относится к небольшому набору, который заполняет некоторые коды поиска. Для какой-то более масштабной работы я определенно выполняю некоторую оптимизацию или некоторые локальные кэшированные данные, чтобы минимизировать такое влияние. Но хорошо бы запомнить, спасибо.