Windows Presentation Foundation (Avalon) Databinding to objects

Databinding to an object datasource is really simple in Windows Presentation Foundation. I didn't find any good samples around, so I'm posting some code here to help you save some time.

My scenarion is really simple, I would like to create an WPF application to visualize my DVD collection. The code also shows how to bind an Image control i WPF to an JPEG image stored inside the SQL Server database (not just a pointer to a file). The code is simplified to only illustrate the main concepts and I have not worked with the design part yet.

First I start with a class to represent the information about a DVD title:

    public class Dvd
    {

        int _dvdId;
        private string _title;
        private byte[] _frontCover;

        public int Id { get { return _dvdId; } }

        public string Title { get { return _title; } }

        public BitmapFrame FrontCover
        {
            get
            {
                BitmapFrame frontCover = System.Windows.Media.Imaging.BitmapFrame.Create(new System.IO.MemoryStream(_frontCover));

                return frontCover;
            }
        }

        public Dvd(
            int id,
            string title,
            byte[] frontCover)
        {
            _dvdId = id;
            _title = title;
            _frontCover = frontCover;
        }

    }

 

The Data Access Layer contains a method to return a list DVD's from the database:

        public static List<Dvd> GetTitles()
        {
            OdbcConnection connection = new OdbcConnection(m_connectionString);

            string selectCommand = @"
                SELECT     DvdId, Title, FrontCover
                FROM         Titles";

            OdbcCommand command = new OdbcCommand(selectCommand, connection);

            List<Dvd> titles = new List<Dvd>();

            connection.Open();
            OdbcDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                Dvd dvd = new Dvd(
                    Convert.ToInt32(reader["DvdId"]),
                    Convert.ToString(reader["Title"]),
                    (byte[])reader["FrontCover"]);

                titles.Add(dvd);

            }

            return titles;
        }

 

Then we have the DvdCollection class which includes a method to return a list of Dvd objects:

using System;
using System.Collections.Generic;
using System.Text;
using DvdLibrary.BusinessEntities;
using DvdLibrary.DataAccessLayer;

namespace DvdLibrary.BusinessLogicLayer
{
    public class DvdCollection
    {
        public static List<Dvd> GetTitles()
        {
            return TitlesDAL.GetTitles();
        }

    }
}

Then in the XAML code-behind, I have this code to retrieve a a list of DVD titles from the business logic layer:

private void OnInit(object sender, EventArgs e)
{
    List<Dvd> titles = DvdCollection.GetTitles();

    DvdList.DataContext = titles;
}

Finally we have the XAML file showing how to do the Databind to the list of DVD titles using a ListBox:

<?Mapping XmlNamespace="DvdLibrary_BusinessLogicLayer" ClrNamespace="DvdLibrary.BusinessLogicLayer" Assembly="DvdLibrary"?>
<Grid
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
xmlns:c="http://schemas.microsoft.com/winfx/markup-compatibility/2005"
xmlns:d="http://schemas.microsoft.com/expression/interactivedesigner/2005"
c:Ignorable="d"
Background="#FFFFFFFF"
x:Name="DocumentRoot"
Width="640"
Height="480"
x:Class="DvdBrowser.Scene1"
Loaded="OnInit"
>

<Grid.Resources>
<ResourceDictionary>
<Storyboard x:Key="OnLoaded" FillBehavior="HoldEnd" BeginTime="{x:Null}" />

<DataTemplate x:Key="DvdItemTemplate">
<Grid>
<Image Source="{Binding FrontCover}"></Image>
<TextBlock Text="{Binding Title}"
FontWeight="Bold" />
</Grid>
</DataTemplate>

</ResourceDictionary>
</Grid.Resources>

 <Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<EventTrigger.Actions>
<BeginStoryboard x:Name="OnLoaded_BeginStoryboard" Storyboard="{DynamicResource OnLoaded}"/>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>

<ColumnDefinition/>
<RowDefinition/>
<ListBox
IsSynchronizedWithCurrentItem="True"
x:Name="DvdList"
Margin="19,23,41,16"
Width="Auto"
Height="Auto"
RenderTransformOrigin="0.5,0.5"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource DvdItemTemplate}"
/>
</Grid>