0

I have 3 projects: Data (Entities, DbContext, etc) WebAPI (ASP.NET CORE) Desktop admin client (WPF, mvvm)

I have books with images.

With the API I can get the images (which are byte []) and books from Data project. At The admin client at the ViewModel I can see the proper byte[] to the proper.

But I don't know how to display at my window.

Relevant code:

MainWindow.xaml

<StackPanel Grid.Row="2" Orientation="Horizontal" Width="600">
    <TextBlock Text="Book ID: " Margin="1" />
    <TextBox Width="50" Text="{Binding BookIdProp}" Margin="0" />
    <Button Content="Show image" Command="{Binding ShowBookImage}" Width="114" IsEnabled="{Binding IsLoaded}" />
</StackPanel>

I want to show the image here:

    <ListBox Grid.Row="3" Grid.ColumnSpan="2" Name="imageListBox" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Disabled">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Image Height="100" Width="Auto" Source="{Binding ShowImageCommand, Converter={StaticResource bookImageConverter}}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

At the viewmodel now I can get the byte[] of image by bookId (textbox). I'm using data transfer objects.

DTO's:

public class ImageDTO
{
    public int Id { get; set; }
    public int BookId { get; set; }
    public byte[] ImageContent { get; set; }
}

public class BookDTO
{
    public int Id { get; set; }
    public String Title { get; set; }
    public String Author { get; set; }
    public ImageDTO Image { get; set; }
    public BookDTO()
    {
        Image = new ImageDTO();
    }

}

ViewModel:

public DelegateCommand ShowImageCommand{ get; private set; }

ShowImageCommand= new ShowImageCommand(param => ShowImage());

private void ShowImage(int id)
{
??
}

Converter:

    public object Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
    {
        if (!(value is Byte[]))
            return Binding.DoNothing;

        try
        {
            using (MemoryStream stream = new MemoryStream(value as Byte[])) 
            {
                BitmapImage image = new BitmapImage();
                image.BeginInit();
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.StreamSource = stream;
                image.EndInit();
                return image;
            }
        }
        catch
        {
            return Binding.DoNothing;
        }
    }

    public object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

How to bind at the viewmodel to show the proper image?

  • Does this answer your question? [Convert byte array to image in wpf](https://stackoverflow.com/questions/9564174/convert-byte-array-to-image-in-wpf) – Pavel Anikhouski Dec 25 '19 at 15:18
  • @PavelAnikhouski No, I have the proper byte[] to bitmap converter function, I just cannot write the function in the viewmodel which show the converted image (or i cannot bind at the view or both). – Jack Bauer Dec 25 '19 at 15:28

2 Answers2

0

Your ViewModel lacks an ObservableCollection for the ListBox to bind it's ItemsSource property.

Each item in the collection should hold the byte[] of the image.

In the ItemTemplate, bind the Image's Source property to the field which holds the byte[] in your item.

0

Binding a image MVVM: It is a bit unclear in your question, but generally you will follow this direction. Hopy that this can help you.

Step 1: First of all, in your Model, create the converter class: You have to bind a instance of BookDTO class, not a byte array:

using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media.Imaging;

namespace YourNamespace.Models
{
    public class BookDTOToImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(value is BookDTO))
            return Binding.DoNothing;

            try
            {
                BookDTO bookDTO = value as BookDTO;
                using (MemoryStream stream = new MemoryStream(bookDTO.Image.ImageContent)) 
                {
                    BitmapImage image = new BitmapImage();
                    image.BeginInit();
                    image.CacheOption = BitmapCacheOption.OnLoad;
                    image.StreamSource = stream;
                    image.EndInit();
                    return image;
                }
            }
            catch
            {
                return Binding.DoNothing;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

Step 2: In your View:

<!--Your code here-->
<Window.Resources>
        <local:BookDTOToImageConverter x:Key="bookDTOToImageConverter"/>
</Window.Resources>
<!--Your code here-->
<!--Your image here-->
<Image Height="100" Width="Auto" Source="{Binding YourImage, Converter={StaticResource bookDTOToImageConverter}}" />

Step 3: In ViewModel, create a full property to bind to View:

using System.ComponentModel;
namespace YourNamespace.ViewModel
{
    public class MainViewModel : INotifyPropertyChanged
    {
        publicMainViewModel()
        {
            // Your code...
        }
        private BookDTO yourBookDTO;
        public BookDTO yourBookDTO
        {
            get { return yourBookDTO; }
            set { yourBookDTO = value; NotifyPropertyChanged("YourBookDTO"); }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string Obj)
        {
            if (PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(Obj));
            }
        }
    }

    public class ImageDTO
    {
        public int Id { get; set; }
        public int BookId { get; set; }
        public byte[] ImageContent { get; set; }
    }
    public class BookDTO
    {
        public int Id { get; set; }
        public String Title { get; set; }
        public String Author { get; set; }
        public ImageDTO Image { get; set; }
        public BookDTO()
        {
            Image = new ImageDTO();
        }
    }
}

Step 4: Your ShowImage method:

private void ShowImage(int id)
{
    this.YourBookDTO = someYourBookDTO; //Image.ImageContent property will be updated automatically
}
Nguyen Van Thanh
  • 805
  • 9
  • 18