C# WPF - загрузить изображение из bytearray в Datagrid

У меня есть форма WPF (я новичок в WPF), которая содержит Datagrid, это Datagrid получает его содержание простым List<AudioFile>, Внутри класса Mp3File который расширяется AudioFile (Это внутри PCL) это метод, называемый GetCoverAsByteArray(), который возвращает обложку загруженного AudioFile как byte[], Теперь я хочу показать изображение обложки в DataGrid, но я не знаю, как это сделать. Не могли бы вы мне помочь?

Вот код, который у меня есть:

<DataGrid x:Name="tvFiles" AutoGenerateColumns="False" MaxColumnWidth="1000" Margin="10,95,10,10" MinHeight="100">
                    <DataGrid.Columns>
                        <DataGridTemplateColumn Header="Cover" Width="*" MinWidth="64">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>

                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTextColumn Header="Filename" Width="*" MinWidth="100" Binding="{Binding Filename}"/>
                        <DataGridTextColumn Header="Artist" Width="*" MinWidth="50" Binding="{Binding Artist}"/>
                        <DataGridTextColumn Header="Title" Width="*" MinWidth="50" Binding="{Binding Title}"/>
                        <DataGridTextColumn Header="Album" Width="*" MinWidth="50" Binding="{Binding Album}"/>
                        <DataGridTextColumn Header="BPM" Width="*" MinWidth="50" Binding="{Binding BPM}"/>
                        <DataGridTextColumn Header="Comment" Width="*" MinWidth="100" Binding="{Binding Comment}"/>
                        <DataGridTextColumn Header="Year" Width="*" MinWidth="40" Binding="{Binding Year}"/>
                        <DataGridTextColumn Header="Key" Width="*" MinWidth="40" Binding="{Binding Key}"/>
                        <DataGridTextColumn Header="Bitrate" Width="*" MinWidth="60" Binding="{Binding Bitrate}"/>
                        <DataGridTextColumn Header="Length" Width="*" MinWidth="50" Binding="{Binding Duration}"/>
                    </DataGrid.Columns>
                </DataGrid>

Большое спасибо за каждую помощь

РЕДАКТИРОВАТЬ 1

Я реализовал Converted, как сказал Деннис, и теперь мой код выглядит так:

class ByteArrayToImageConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {

        byte[] bytes = (byte[])value;

        if (bytes == null || bytes.Length == 0) return null;

        var image = new BitmapImage();
        using (var mem = new MemoryStream(bytes)) {
            mem.Position = 0;
            image.BeginInit();
            image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.UriSource = null;
            image.StreamSource = mem;
            image.EndInit();
        }
        image.Freeze();
        return image;
    }

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

<Window.Resources>
    <local:ByteArrayToImageConverter x:Key="converter" />
</Window.Resources>

<DataGrid x:Name="tvFiles" AutoGenerateColumns="False" MaxColumnWidth="1000" Margin="10,95,10,10" MinHeight="100">
                    <DataGrid.Columns>
                        <DataGridTemplateColumn Header="Cover" Width="*" MinWidth="64">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Image Source="{Binding GetCoverAsByteArray, Converter={StaticResource converter}}"/>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTextColumn Header="Filename" Width="*" MinWidth="100" Binding="{Binding Filename}"/>
                        <DataGridTextColumn Header="Artist" Width="*" MinWidth="50" Binding="{Binding Artist}"/>
                        <DataGridTextColumn Header="Title" Width="*" MinWidth="50" Binding="{Binding Title}"/>
                        <DataGridTextColumn Header="Album" Width="*" MinWidth="50" Binding="{Binding Album}"/>
                        <DataGridTextColumn Header="BPM" Width="*" MinWidth="50" Binding="{Binding BPM}"/>
                        <DataGridTextColumn Header="Comment" Width="*" MinWidth="100" Binding="{Binding Comment}"/>
                        <DataGridTextColumn Header="Year" Width="*" MinWidth="40" Binding="{Binding Year}"/>
                        <DataGridTextColumn Header="Key" Width="*" MinWidth="40" Binding="{Binding Key}"/>
                        <DataGridTextColumn Header="Bitrate" Width="*" MinWidth="60" Binding="{Binding Bitrate}"/>
                        <DataGridTextColumn Header="Length" Width="*" MinWidth="50" Binding="{Binding Duration}"/>
                    </DataGrid.Columns>
                </DataGrid>

Теперь я получаю следующее сообщение при загрузке AudioFile в Datagrid:

Ошибка System.Windows.Data: 40: Ошибка пути BindingExpression: свойство 'GetCoverAsByteArray()' не найдено для объекта ' ''Mp3File' (HashCode=54312533)'. BindingExpression: Путь =GetCoverAsByteArray(); DataItem='Mp3File' (HashCode=54312533); целевым элементом является "Изображение" (Name=''); Свойство target - "Source" (тип "ImageSource")

Ошибка System.Windows.Data: 40: Ошибка пути BindingExpression: свойство 'Key' не найдено в 'object' ''Mp3File' (HashCode=54312533)'. BindingExpression:Path=Key; DataItem='Mp3File' (HashCode=54312533); целевым элементом является TextBlock (Name=''); Свойство target - "Текст" (тип "Строка").

2 ответа

Решение

Привязка данных работает только для свойств. Вы должны добавить свойство к AudioFile класс для возврата данных обложки. Если вы не хотите менять AudioFile по некоторым причинам затем сопоставьте его / оберните его в модель представления и поместите свойство в эту модель представления.

Тогда у вас будет два варианта.

Опция 1.

Вместо public byte[] CoverAsByteArray { get; } Вы можете написать свойство, которое возвращает ImageSource например, что-то вроде public ImageSource CoverAsImageSource { get; },

XAML будет выглядеть так:

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <Image Source="{Binding CoverAsImageSource}"/>
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

Вариант 2

Вы можете написать конвертер значений для преобразования byte[] значение в ImageSource,

В этом случае XAML будет выглядеть так:

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <Image Source="{Binding CoverAsByteArray, Converter={StaticResource YourConverterKey}}"/>
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

При условии, что byte[] представляет растровое изображение, вы можете использовать, например, этот ответ, чтобы преобразовать его в соответствующий источник изображения.

Вы можете использовать Microsoft.WindowsAPICodePack.Shell, чтобы получить изображение из вашего mp3 файла

private string cacheLocalFile(string mp3fileName)
    {
        try
        {
            using (var shell = ShellFile.FromParsingName(mp3fileName))
            {
                Bitmap bmp = shell.Thumbnail.Bitmap;
                var cachedFileName = shell.Properties.System.FileName.Value;
                bmp.Save(Path.Combine(AppCacheDirectory, cachedFileName), ImageFormat.Jpeg);
                bmp.Dispose();
                return Path.Combine(AppCacheDirectory, cachedFileName);
            }
        }
        catch
        {
            return String.Empty;
        }

    }

Вы только что получили миниатюру, сохраняете ее в файл и возвращаете файл src в элемент Image, если вы не хотите кэшировать изображение, вы можете просто преобразовать растровое изображение в bitmapImage и связать его с видимым элементом изображения вообще.

Другие вопросы по тегам