Results 1 to 2 of 2

Thread: [RESOLVED] Binding Datatable image column to Datagrid column

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2011
    Location
    England
    Posts
    421

    Resolved [RESOLVED] Binding Datatable image column to Datagrid column

    Hello,

    I have just started my first project with WPF and looking at how I can bind a Datatable to a Datagrid. I can see that my text column binds properly but that an image column within the Datatable does not show my images in the Datagrid.

    Here is the XAML I am using:
    Code:
    <DataGrid x:Name="grdImage" Grid.Column="0" AutoGenerateColumns="False" CanUserAddRows="False" BorderThickness="0,1,1,1" ItemsSource="{Binding}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Width="SizeToCells" IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding colImage}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="Image Filename" Width="*" Binding="{Binding colPath}"/>
        </DataGrid.Columns>
    </DataGrid>
    And this is the code I am using in the editor:
    Code:
    #Region " Properties "
    
      Public Property ImageCollection As DataTable
        Get
          Return TryCast(Me.grdImage.DataContext, DataTable)
        End Get
        Set(value As DataTable)
          Me.grdImage.DataContext = value
        End Set
      End Property
    
    #End Region
    
    #Region " Buttons "
    
      Private Sub btnOpenFile_Click(sender As Object, e As RoutedEventArgs) Handles btnOpenFile.Click
        Dim oFile As New OpenFileDialog
        With oFile
          .Title = "Select image(s) to resize"
          .InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
          .Multiselect = True
        End With
        If oFile.ShowDialog() Then
          Dim T As New Thread(AddressOf Me.ImportImages)
          T.Start(New ImportImagesArguments With {
                  .ImportMode = ImportImagesArguments.Mode.SelectedFiles,
                  .RootFolder = oFile.InitialDirectory,
                  .ImagePaths = oFile.FileNames})
        End If
      End Sub
    
    #End Region
    
    #Region " Classes "
    
      Public Class ImportImagesArguments
        Public Enum Mode
          AllFilesInFolder
          AllFilesInFolderWithRecursion
          SelectedFiles
        End Enum
    
        Public Property ImportMode As Mode
        Public Property RootFolder As String
        Public Property ImagePaths As String()
        Public Property ImageTable As DataTable
      End Class
    
    #End Region
    
    #Region " Private Methods "
    
      Private Function LoadImageThumbnail(ByVal ImagePath As String, Optional ThumbSize As Integer = 32) As Image
        Dim Callback As New Image.GetThumbnailImageAbort(AddressOf ThumbnailCallback)
        Dim SrcBMP As New Bitmap(ImagePath)
        If SrcBMP.Width < ThumbSize Then
          ThumbSize = SrcBMP.Width
        End If
        If SrcBMP.Height < ThumbSize Then
          ThumbSize = SrcBMP.Height
        End If
        Return SrcBMP.GetThumbnailImage(ThumbSize, ThumbSize, Callback, IntPtr.Zero)
      End Function
    
      Private Function ThumbnailCallback() As Boolean
        Return False
      End Function
    
    #End Region
    
    #Region " Threading "
    
      Private Sub ImportImages(state As Object)
        Dim Args As ImportImagesArguments = CType(state, ImportImagesArguments)
        Args.ImageTable = New DataTable
        Args.ImageTable.Columns.Add("colImage", GetType(Image))
        Args.ImageTable.Columns.Add("colPath", GetType(String))
        For Each ImgPath As String In Args.ImagePaths
          Dim DRow As DataRow = Args.ImageTable.NewRow
          DRow.Item("colImage") = Me.LoadImageThumbnail(ImgPath)
          DRow.Item("colPath") = ImgPath
          Args.ImageTable.Rows.Add(DRow)
        Next ImgPath
        Me.ImportImagesComplete(Args)
      End Sub
    
      Private Delegate Sub DEL_ImportImagesComplete(state As Object)
      Private Sub ImportImagesComplete(state As Object)
        If Not Dispatcher.CheckAccess Then
          Dispatcher.Invoke(New DEL_ImportImagesComplete(AddressOf Me.ImportImagesComplete), New Object() {state})
        Else
          Dim Args As ImportImagesArguments = CType(state, ImportImagesArguments)
          Me.ImageTable = Args.ImageTable
          Me.ImageCollection = Args.ImageTable
        End If
      End Sub
    
    #End Region
    I have found a lot of examples via Google that demonstrate how to bind an image to a static resource or to an image based upon it's filepath, however I am struggling to find an example that shows how I can bind to images either within a Collection or a Datatable where the image has already been loaded into memory.

    Any help on this would be appreciated.

    Thanks,
    Jay

  2. #2

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2011
    Location
    England
    Posts
    421

    Re: Binding Datatable image column to Datagrid column

    After some further reading I have realised that a System.Drawing.Image cannot be bound to a System.Windows.Controls.Image used in WPF. The solution I found is to create an IValueConverter class, add it as a local resource to the XAML and then specify the converter in the Source binding of the image column within my DataGrid. When testing with my original code it seems to work as expected.

    The code for these additions is as follows (in case anybody else finds it useful):

    XAML added within the Window element:
    Code:
    <Window.Resources>
        <local:BitmapToImageSourceConverter x:Key="BitmapToImageConverter" />
    </Window.Resources>
    My updated Image Binding within the DataGrid XAML:
    Code:
    <Image Source="{Binding colImage, Converter={StaticResource BitmapToImageConverter}}"/>
    And finally the class for the image conversion which sits outside of the MainWindow class in the code editor:
    Code:
    Public Class BitmapToImageSourceConverter : Implements IValueConverter
    
      Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
        Return Interop.Imaging.CreateBitmapSourceFromHBitmap(
            CType(value, Bitmap).GetHbitmap,
            IntPtr.Zero,
            Int32Rect.Empty,
            BitmapSizeOptions.FromEmptyOptions)
      End Function
    
      Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
      End Function
    
    End Class
    Regards,
    Jay

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width