Can't Get My Image to Appear in an Image Container

RogerSchlueter-7899 1,236 Reputation points
2020-04-03T16:04:42.707+00:00

I have all the parts to display an image in the wpf Image control but I cant' get them all wired together. First I have a Picture class as follows ((ignoring irrelevant code):

Public Class Picture .... Private _Image As Byte() Private _Title As String End Class

I have a picture stored in a varbinarymax) field in an SQL Server database which I retrieve as follows (ignoring irrelevant code):

Dim pic As Picture
Using con As New SqlConnection(My.Settings.....)
Dim com As New SqlCommand("Get_Image", con) With ....}
com.Parameters.Add("@ImageID", SqlDbType.Int).Value = 3
con.Open()
Dim rdr As SqlDataReader = com.ExecuteReader
rdr.Read()
pic = New Picture With {.ImageID = rdr.GetInt32(0), .ImageDate = rdr.GetDateTime(1), .Title = rdr.GetString(2)}
Length = CInt(rdr.GetInt64(3))
MyData = New Byte(Length - 1) {}
rdr.GetBytes(4, 0, MyData, 0, Length)
End Using

Then I display it in the Image control named "picPerson"

Dim biImg As New BitmapImage()
Dim ms As New MemoryStream(MyData)
biImg.BeginInit()
biImg.StreamSource = ms
biImg.EndInit()
picPerson.Source = biImgDim biImg As New BitmapImage()
Dim ms As New MemoryStream(MyData)
biImg.BeginInit()
biImg.StreamSource = ms
biImg.EndInit()
picPerson.Source = biImg

Then I display it in the Image control named "picPerson"

Dim biImg As New BitmapImage()
Dim ms As New MemoryStream(MyData)
biImg.BeginInit()
biImg.StreamSource = ms
biImg.EndInit()
picPerson.Source = biImg

There is nothing displayed in picPerson but I also don't get any error messages or excepitons thrown. Where did I go off the rails?

Edit 1:

I appreciate all the effort you went to but it is to no avail. Line 42 gives a compile-time error. I have tried to rescue the ideas you have provided and now have this:

Dim Length As Integer
        Dim MyData() As Byte
        Dim pic As Picture
        Using con As New SqlConnection(My.Settings.PIMConnectionString)
            Dim com As New SqlCommand("Get_Image", con) With {.CommandType = CommandType.StoredProcedure}
            com.Parameters.Add("@ImageID", SqlDbType.Int).Value = 3   'cp.PictureID
            con.Open()
            Dim rdr As SqlDataReader = com.ExecuteReader
            rdr.Read()
            pic = New Picture With {.ImageDate = rdr.GetDateTime(0), .Title = rdr.GetString(1)}
            Length = CInt(rdr.GetInt64(2))
            MyData = New Byte(Length) {}
            rdr.GetBytes(3, 0, MyData, 0, Length)
        End Using
        Dim biImg As New BitmapImage()
        Dim ms As New MemoryStream(MyData)
        ms.Read(MyData, 0, Length)
        biImg.BeginInit()
        biImg.StreamSource = ms
        biImg.EndInit()
        picPerson.Source = biImg

Unfortunately, this yields this run-time error:

The image cannot be decoded. The image header might be corrupted.

There is no need to provide a complete solution. I'm pretty sure the code listed above is where the problem is. Please take a look to see what is wrong.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,681 questions
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-04-04T09:35:55.23+00:00

    Hi Roger, try following demo:

    XAML:

    <Window x:Class="Window001"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Demo load picture from database" Height="450" Width="800">
      <Window.DataContext>
        <local:Window001VM/>
      </Window.DataContext>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Image Source="{Binding Picture}"/>
        <StackPanel Grid.Column="1">
          <Button Content="Prepare Database" Command="{Binding Cmd}" CommandParameter="Create" Margin="5"/>
          <Button Content="Load Picture" Command="{Binding Cmd}" CommandParameter="Load" Margin="5"/>
        </StackPanel>
      </Grid>
    </Window>
    

    ViewModel:

    Imports System.ComponentModel
    Imports System.Data
    Imports System.Data.SqlClient
    Imports System.IO
    Imports System.Runtime.CompilerServices
    
    Public Class Window001VM
      Implements INotifyPropertyChanged
    
      Public Property Picture As BitmapImage
    
      Public ReadOnly Property Cmd As ICommand = New RelayCommand(AddressOf CmdExec)
    
      Private Sub CmdExec(obj As Object)
        Select Case obj.ToString
          Case "Create"
            Using cn As New SqlConnection(My.Settings.cnSQL)
              cn.Open()
              Using cmd As New SqlCommand With {.Connection = cn}
                ' delete previous table in SQL Server 2016 and above
                'cmd.CommandText = "DROP TABLE IF EXISTS Table1;"
                ' delete previous table in previous versions of SQL server 2016
                cmd.CommandText = "If OBJECT_ID('Table1', 'U') IS NOT NULL DROP TABLE IF EXISTS Table1;"
                Debug.Print($"Return value Drop: {cmd.ExecuteNonQuery}")
                ' Cretae Table
                cmd.CommandText = "CREATE Table Table1([ID] Integer Identity, [Picture] image, CONSTRAINT [PK_Table1] PRIMARY KEY ([ID]));"
                Debug.Print($"Return value Create Table: {cmd.ExecuteNonQuery}")
                ' Insert Record with Picture from file system
                cmd.CommandText = "INSERT Table1([Picture]) VALUES(@pict);"
                cmd.Parameters.Add("@pict", SqlDbType.Image).Value = File.ReadAllBytes("Image.jpg")
                Debug.Print($"Return value Insert Picture: {cmd.ExecuteNonQuery}")
              End Using
            End Using
          Case "Load"
            Using cn As New SqlConnection(My.Settings.cnSQL)
              cn.Open()
              Using cmd As New SqlCommand With {.Connection = cn}
                cmd.CommandText = "SELECT * FROM Table1;"
                Dim rdr = cmd.ExecuteReader
                rdr.Read()
                Dim buf = CType(rdr(1), Byte())
                Dim ms As New MemoryStream(buf)
                Dim img As New BitmapImage()
                img.BeginInit()
                img.StreamSource = ms
                img.EndInit()
                Picture = img
                OnPropertyChanged(NameOf(Picture))
              End Using
            End Using
        End Select
      End Sub
    
      Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
      Private Sub OnPropertyChanged(<CallerMemberName> Optional propName As String = "")
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
      End Sub
    
    End Class
    

1 additional answer

Sort by: Most helpful
  1. Alex Li-MSFT 1,096 Reputation points
    2020-04-09T07:15:11.267+00:00

    Hi,

    Welcome to our Microsoft Q&A platform!

    You can try the following code:

    reader.Read()
    Dim buf As MemoryStream = New MemoryStream(CType(reader(1), Byte()))
    picPerson.Source = BitmapFrame.Create(buf, BitmapCreateOptions.None, BitmapCacheOption.OnLoad)
    

    Thanks.