简体   繁体   中英

WPF xaml how to show image from API on button click?

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?

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.

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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM