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 и связать его с видимым элементом изображения вообще.