I’m working on a WPF app for my wife who coaches our local high school track team. One of the features she wanted was to have some images for different players and teams and, religious debate aside, I have chosen to save these in SQL Server 2005. I’m using NHibernate for all my data access which has been a great experience (my first). Impressively, NHibernate supports SQL Server Image columns via the inherent Byte[] type (See Section 5.1.9 of the docs). This made adding the Image to my classes very easy.
Here’s a snippet of my class with the corresponding NHibernate Mapping Xml File:
/* Class */[Serializable]public class Organization : INotifyPropertyChanged{ //... public byte[] Image { get { return _image; } set { _image = value; OnPropertyChanged("Image"); } } //...}<!-- Mapping --><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false"> <class name="Cromwell.MyApp.Organization, Cromwell.MyApp" table="dbo.Organization"> <id name="Id" type="Int32" column="Id" unsaved-value="0"> <generator class="native" /> </id> <many-to-one name="Type" class="Cromwell.MyApp.OrganizationType, Cromwell.MyApp" column="Type" not-null="true"/> <property name="Name" type="String" length="255" column="Name" not-null="true"/> <property name="Address1" type="String" length="255" column="Address1" not-null="false"/> <property name="Address2" type="String" length="255" column="Address2" not-null="false"/> <property name="City" type="String" length="255" column="City" not-null="false"/> <property name="State" type="String" length="2" column="State" not-null="false"/> <property name="PostalCode" type="String" length="7" column="PostalCode" not-null="false"/> <property name="Image" type="Byte[]" column="Image" not-null="false" /> </class></hibernate-mapping>
The key to binding this Image property on my WPF forms is the Binding Converter property. This property allows you to specify any class which implements System.Windows.Data.IValueConverter to act as an intermediary between your bind data and WPF. In my case, the goal was to turn a byte[] property, Image, into a BitmapImage which the an <Image /> control/element can display.
Here’s what I came up with:
class BinaryImageConverter : IValueConverter{ object IValueConverter.Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) { if(value != null && value is byte[]) { byte[] bytes = value as byte[]; MemoryStream stream = new MemoryStream( bytes ); BitmapImage image = new BitmapImage(); image.BeginInit(); image.StreamSource = stream; image.EndInit(); return image; } return null; } object IValueConverter.ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) { throw new Exception( "The method or operation is not implemented." ); }}
Here’s how I used it in my WPF Page:
<Page x:Class="Cromwell.MyApp.EditOrganization" ... xmlns:converts="clr-namespace:Cromwell.MyApp.Converters" > <Page.Resources> <converts:BinaryImageConverter x:Key="imgConverter" /> </Page.Resources> <Grid> <!-- Image Control --> <Image Source="{Binding Path=Image, Converter={StaticResource imgConverter}}" Stretch="UniformToFill" StretchDirection="Both"> <Image.BitmapEffect> <DropShadowBitmapEffect Color="Black" /> </Image.BitmapEffect> </Image> </Grid></Page>
I’m going to have to spend some time in the WPF profiler, but this is a big step. Pretty cool how simple it was and very clean.
This is good. Thanks
can you put the source code please
I’ll do what I can. All the code is above so you could pretty easily (couple minutes) copy and paste this into your own visual studio project.
Ive been researching this and I’ll have to agree
this is excellent but how will i get the bytes into the database in the first place?
Can i do this with WPF Data Binding? If i place the image i want to upload in an image control, how do i get the app to insert the bytes and not the image path?
Thanks
Thanks so much. Pretty straight forward, but did not get this running without your idea. Using this also to get Images from NHibernate and a MySQL db, then converting those images in a datatemplate for listbox items.