/Home /Archive /Syndicate /Blog /Support /About /Contact  
All Visual Basic Feeds in one place!





 

In the previous blogs on ValueConverters - here and here - the conversion was from Integer type to Brush. In this blog I will cover the situation where you want to include a small image or icon in the ListView.

There are various alternatives here. You could hard code the image path into the collection, but the problem may be that you don't know the exact image paths at the time the collection is created. The approach I want to use is where you parse the data as it feeds through the binding and you select a stored image from the hard drive, the selection being based on the value of a specific field. This decouples the details of the image from the collection itself, which may be useful in many situations.

The DrinkProduct class looks like this: 

Public Class DrinkProduct

    Enum MaterialType

        Granules

        Leaf

        Liquid

        Paste

        Powder

        Other

    End Enum

    Sub New(ByVal ID As String, ByVal Name As String, ByVal PackType As String, _

           ByVal BaseMaterial As MaterialType, ByVal Sales As Integer, ByVal Qty As Integer)

        Me.ProductID = ID

        Me.ProductName = Name

        Me.PackageType = PackType

        Me.Material = BaseMaterial

        Me.AnnualSales = Sales

        Me.Quantity = Qty

    End Sub

 

    Private _ProductID As String

    Public Property ProductID() As String

        Get

            Return _ProductID

        End Get

        Set(ByVal value As String)

            _ProductID = value

        End Set

    End Property

 

    Private _ProductName As String

    Public Property ProductName() As String

        Get

            Return _ProductName

        End Get

        Set(ByVal value As String)

            _ProductName = value

        End Set

    End Property

 

    Private _PackageType As String

    Public Property PackageType() As String

        Get

            Return _PackageType

        End Get

        Set(ByVal value As String)

            _PackageType = value

        End Set

    End Property

 

 

    Private _Material As MaterialType

    Public Property Material() As MaterialType

        Get

            Return _Material

        End Get

        Set(ByVal value As MaterialType)

            _Material = value

        End Set

    End Property

 

    Private _quantity As Integer

    Public Property Quantity() As Integer

        Get

            Return _quantity

        End Get

        Set(ByVal value As Integer)

            _quantity = value

        End Set

    End Property

 

 

    Private _annualsales As Integer

    Public Property AnnualSales() As Integer

        Get

            Return _annualsales

        End Get

        Set(ByVal value As Integer)

            _annualsales = value

        End Set

    End Property

 

    Public Shared Function StockCheck() As List(Of DrinkProduct)

        Dim CurrentProducts As New List(Of DrinkProduct)

        With CurrentProducts

            .Add(New DrinkProduct("CF1kg", "Coffee Powder", "1 Kg", MaterialType.Powder, 15684, 1276))

            .Add(New DrinkProduct("CFB500", "Ground Coffee", "500 g", MaterialType.Powder, 22785, 12856))

            .Add(New DrinkProduct("CFG500", "Coffee Granules", "500 g", MaterialType.Granules, 19233, 5907))

            .Add(New DrinkProduct("Te500", "Tea", "500 g", MaterialType.Leaf, 8544, 235))

            .Add(New DrinkProduct("TeInst500", "Instant Tea", "500 g", MaterialType.Powder, 1009, 22))

            .Add(New DrinkProduct("SMlk1lt", "Skimmed Milk", "1 Litre", MaterialType.Liquid, 28012, 2650))

            .Add(New DrinkProduct("HiJ300", "HiJuice Drink Mix", "300 g", MaterialType.Other, 578, 179))

            .Add(New DrinkProduct("Sm400", "Smoothie", "400ml", MaterialType.Paste, 9346, 3284))

            .Add(New DrinkProduct("Beef300", "Beef Drink", "300 g", MaterialType.Granules, 8316, 1965))

            .Add(New DrinkProduct("Beef750", "Beef Drink", "750 g", MaterialType.Granules, 7612, 359))

 

        End With

 

        Return CurrentProducts

    End Function

 

End Class 

The Enumeration named 'MaterialType' identifies whether the product is powder, liquid, granule, etc and this is what I will use as the key for selecting the appropriate image.

The ValueConverter class is similar to those used in the previous blogs - IValueConverter requires the two methods named Convert and ConvertBack. ConvertBack serves no purpose is this scenario, so only throws a not implemented exception. 

Public Class MaterialToImagePathConverter

    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

        Select Case value.ToString

            Case "Powder"

                Return "Images/powderbrown.jpg"

            Case "Liquid"

                Return "Images/liquiddrop4.jpg"

            Case "Leaf"

                Return "Images/leaf.jpg"

            Case "Granules"

                Return "Images/granules.jpg"

            Case "Paste"

                Return "Images/Paste2.jpg"

            Case Else

                Return "Images/questionmark.jpg"

        End Select

 

    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

        Throw New NotImplementedException()

    End Function

End Class 

As before, the parameter named 'value' is an Object type which is the key element in the conversion process. It contains the value that is to be converted. The conversion is simple in this case because all we need is to find the string value of the enumeration that is being passed in. So the basic ToString method will work fine.

Once we have a String value, this is compared against the various possibilities. A string which represents the file path to an appropriate image is returned by the converter. I've chosen to include the image files in the project, but of course they could be stored externally and still be accessed in the same way.

The next steps are the same as for the previous examples in the earlier blogs. First, map the current assembly to an XML namespace in Application.xaml:  

  xmlns:local="clr-namespace:WPFListView2"  

Then create an instance of the converter class in Application.xaml and give it a key: 

    <local:MaterialToImagePathConverter x:Key="IconConverter" /> 

Next, create a DataTemplate for the new column of the ListView:  

    <DataTemplate x:Key="IconCellTemplate">

            <Image Margin="0,0,1,3" Height="18" Width="25"

          Stretch="Fill"     

        Source="{Binding Path=Material, Converter={StaticResource IconConverter}}" />

    </DataTemplate> 

In the above markup, the Binding Path is the Material field, the converter is the MaterialToImagePathConverter instance created above.

Finally, the ListView in the Window needs to have a new column added in which the images can be displayed: 

          <GridViewColumn

           CellTemplate="{StaticResource IconCellTemplate}">

          </GridViewColumn> 

And now you are all set. The finished Window displays as shown below:

 

   

 

For completeness, the full markup for the Window which contains the ListView is shown here: 

<Window x:Class="Window2"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Title="Image Path Converter Demo" Height="360" Width="450">

  <Grid>

 

    <ListView Name="ProductsListView"

         ItemsSource="{Binding}"

           Margin="5" >

 

      <ListView.ItemContainerStyle>

        <Style TargetType="ListViewItem">

          <Setter Property="HorizontalContentAlignment" Value="Stretch" />

        </Style>

      </ListView.ItemContainerStyle>

 

      <ListView.View>

        <GridView>

          <!-- Icon column -->

          <GridViewColumn

           CellTemplate="{StaticResource IconCellTemplate}">

          </GridViewColumn>

          <!-- Product ID -->

          <GridViewColumn

           HeaderTemplate="{StaticResource IDColHeader}"

          CellTemplate="{StaticResource IDCellTemplate}">

          </GridViewColumn>

          <!-- Product Name -->

          <GridViewColumn

           HeaderTemplate="{StaticResource NameColHeader}"

           CellTemplate="{StaticResource NameCellTemplate}">

          </GridViewColumn>

          <!-- Pack Size -->

          <GridViewColumn

           HeaderTemplate="{StaticResource PackageColHeader}"

           CellTemplate="{StaticResource PackCellTemplate}">

          </GridViewColumn>

        </GridView>

      </ListView.View>

    </ListView>

 

  </Grid>

</Window> 

Of course you are not forced to use the ValueConverter approach for this task. You could rewrite the class and give it an ImagePath property. Then in the code-behind run a function with a similar Select Case block to the one used above, passing back the appropriate path to the ImagePath property. The collection would be amended on the fly to include this data and finally the amended collection would be used as the DataContext. The Binding Path for the Image Source property would be that field. Personally, I think the ValueConverter is neater. And if the data comes from an external source, perhaps in the form of an XML file, then using the ValueConverter is almost certainly a better way.

© 2005 Serge Baranovsky. All rights reserved.
All feed content is property of original publisher. Designated trademarks and brands are the property of their respective owners.

This site is maintained by SubMain(), a division of vbCity.com, LLC