views:

1130

answers:

3

I have a ListView in WPF that is databound to a basic table that I pull from the database. The code for the ListView is as follows:

<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>

The IdCst column is a foreign key to a separate table, and I'd like to display the actual name field from that table instead of just the Id. Does anybody know how to set a databinding, or is there an event, such as OnItemDataBound, that I could intercept to modify the display?

A: 

This blog post may help:

...I assumed the foreign key should be bound to the ‘SelectedValue’ property, and there is an ItemSource that I can bind to my fact table so the drop down is populated.

At this point my dropdown worked, but nothing would appear in the combobox. I finally noticed a ‘SelectedItemPath’ property - I assumed this would be the name of the field in my dropdown that was associated to my foreign key. Sure enough, that’s exactly what it is.

Mitch Wheat
+1  A: 

I'd add a new property to your underlying class:

Public ReadOnly Property NameCst() as String
    Get
        Return Names.LookupName(Me.IdCst)
    End Get
End Property

or something similar. Note that you'll probably have to include a Notify Property Changed event in your .IdCst setter for "NameCst".

An alternative is to write a ValueConverter that does the lookup, but that's pretty heavy weight for something so simple.

Bob King
A: 

BOO YAH!!!

I looked at the samples here, dug off a few of the references from other posts here, and found the answer... IValueConverter ... an interface that can be used with WPF that will convert values at the point of binding. It is a little tricky to put together at first, but not that difficult.

The first step is to create a simple lookup or converter class that implements the IValueConverter interface. For my solution, I did this:

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

Note: I am not utilizing the ConvertBack method, but it is required by the interface.

From there you need to add a reference to the namespace in your XAML header section:

<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">

Then in your Windows.Resources section, you can reference the converter, and in my case, I created a static reference to the CollectionViewSource that would be storing the data:

<Window.Resources>
   <CollectionViewSource Source="{Binding Source={x:Static Application.Current}, Path=CardDetails}" x:Key="CardDetails">         
   </CollectionViewSource>

   <c:SetIdToNameConverter x:Key="SetConverter"/>      
</Window.Resources>

Then finally, in the ListView that was part of the initial problem, you add the converter reference:

<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>

So the great part now is that when I trigger an event that has a Card Id, all I need to do is reset set the CollectionViewSource...

DirectCast(Me.FindResource("CardDetails"), CollectionViewSource).Source = taCardDetails.GetDataById(CardId)

...and all the binding elements of WPF do the rest!

The nice thing about is is that I can easily create other converters, add them to various DataTemplates or columns elsewhere in the application, and once I get all of the data into the WPF app itself, the conversions can be conducted without going to the database.

Dillie-O
Quick note. I found that compiling the converter class before adding all the XAML code seems to help eliminate some of the "nags" that it will give you until everything is compiled together.
Dillie-O
Sorry to burst your bubble, but this converter will hit the database at least once for each row.
Robert Jeppesen
True true. However that is currently for a small set that populates some lookup codes. For some larger work, I'm definitely doing some optimization, or some local cached data to minimize that kind of impact. But is good to remember, thanks.
Dillie-O