问题
I've got a WPF Form (I am totally a beginner in WPF) which contains a Datagrid
. This Datagrid
gets its Content by a simple List<AudioFile>
. Inside the class Mp3File
which extends AudioFile
(It's inside a PCL) is a method called GetCoverAsByteArray()
, which returns the cover of a loaded AudioFile
as a byte[]
.
Now i want to show the cover Image in the DataGrid
, but i don't know how to do it. Can you please help me?
Here is the code i have so far:
<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>
Thanks a lot for every help
EDIT 1
I implemented a Converted like Dennis has said and now my code looks like this:
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>
Now i get the following Message when loading a AudioFile into the Datagrid:
System.Windows.Data Error: 40 : BindingExpression path error: 'GetCoverAsByteArray()' property not found on 'object' ''Mp3File' (HashCode=54312533)'. BindingExpression:Path=GetCoverAsByteArray(); DataItem='Mp3File' (HashCode=54312533); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource')
System.Windows.Data Error: 40 : BindingExpression path error: 'Key' property not found on 'object' ''Mp3File' (HashCode=54312533)'. BindingExpression:Path=Key; DataItem='Mp3File' (HashCode=54312533); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
回答1:
Data binding works for properties only. You have to add a property to AudioFile
class to return cover data. If you don't want to change AudioFile
for some reasons, then map it/wrap it into view model, and place property into that view model.
Then you'll have two options.
Option 1.
Instead of public byte[] CoverAsByteArray { get; }
you can write a property, which returns ImageSource instance, something like public ImageSource CoverAsImageSource { get; }
.
XAML will look like this:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding CoverAsImageSource}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
Option 2.
You can write a value converter to convert byte[]
value into ImageSource
.
In this case, XAML will look like this:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding CoverAsByteArray, Converter={StaticResource YourConverterKey}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
Assuming, that byte[]
represents a bitmap, you can use, e.g., this answer to convert it to appropriate image source.
回答2:
you can use Microsoft.WindowsAPICodePack.Shell to get image from your mp3 file
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;
}
}
you just got thumbnail, saves it to the file and returns file src to Image element, if you don't want to cache image you can just convert bitmap to bitmapImage and bind it to image element in view at all.
来源:https://stackoverflow.com/questions/33214390/c-sharp-wpf-load-image-from-bytearray-into-datagrid