July 12, 2008

WPF: Binding an array of objects to a ListBox

Posted in Databinding, ListBox, Uncategorized, WPF tagged , , , at 11:23 pm by Mike

One way Windows Presentation Foundation (WPF) brings data to a user is through data binding. This post creates an object bounded example program using a WPF ListBox.  The example uses a typical Model-View-Controller  architecture.

Description:

Imagine receiving the task of displaying some array of objects.  One approach would be to iterate over the array and perform a “toString” on each object outputting the concatenation of all strings.  This is silly, let alone plain inefficient. Sure, if what needs to be displayed changes you can simply update the respective object’s toString implementation and be done. However, if the object has changed such that representing it by a simple string is not descriptive enough, then there is a big problem.  A lot of pieces will have to change in order to accommodate the displaying of the array in some other way. Using the M-V-C architecture creates a helpful layering of business and visual logic specific operations giving some of the wanted flexibility.

The source code for this post is available here.

For time and simplicity, it is assumed that data has arrived at the controller from some data source.  This data should be displayed to the user in a “pleasing manner.” (At least what I consider pleasing for a quick example.)

The type of data to be displayed is contained in a small object (“ClassInfo”) as defined below. For now it will only hold the name of a particular class.  (We will later update it with another piece of data using a different data type.)

ClassInfo.cs:

namespace ObjectDatabindingExample

{

    public class ClassInfo

    {

        public string Name { get; set; }

    }

}

The next class definition we need to see is the controller.  As mentioned earlier, it is assumed that the controller has already received the array of ClassInfo objects it needs to display.  The controller class will begin small and only contain the array of ClassInfo objects. See below.

ClassController.cs:

namespace ObjectDatabindingExample

{

    public class ClassController

    {

        #region Private Members

 

        private readonly ClassInfo[] _data = new ClassInfo[] {

            new ClassInfo() { Name = “Calculus II” },

            new ClassInfo() { Name = “Physics” },

            new ClassInfo() { Name = “AI Algorithms and Design Considerations” },

            new ClassInfo() { Name = “Programming Patterns” },

            new ClassInfo() { Name = “Computer Networks” },

            new ClassInfo() { Name = “Building and Programming Robots” },

            new ClassInfo() { Name = “Distributed Systems” }

        };

 

        #endregion

    }

}

Thinking about this for a moment, it seems we are going to want to display this data somehow.  Next up for creation is the View class. (in this case “ClassView.”) See below for the XAML, the code behind is simply default for now.

ClassView.xaml:

<Window x:Class=”ObjectDatabindingExample.ClassView”

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

    Title=”Object Data Binding Example” Height=”300″ Width=”300″>

    <Grid>

    </Grid>

</Window>

ClassView is the “View”,  and ClassController is the “Controller” in the MVC architecture.  The next class needed is a “Model” (in this case “ClassModel”) that will be what the viewer binds to and what the controller updates with data.  See ClassModel’s initial definition below.

ClassModel.cs:

namespace ObjectDatabindingExample

{

    public class ClassModel

    {

    }

}

Okay, this makes up the initial architecture of this small example.  However, no linkage has been done between the objects/classes so nothing interesting is happening yet.  We know that the controller needs to update the model with its data, and that ClassView will be bound to properties on that model. Let’s give the model a property that will store the ClassInfo objects given to it by the controller.  We’ll use an ObservableCollection in the model class so that ClassView can bind directly to the property. ClassModel’s definition changes to the following.

ClassModel.cs:

using System.Collections.ObjectModel;

 

namespace ObjectDatabindingExample

{

    public class ClassModel

    {

        public ObservableCollection<ClassInfo> Classes { get; set; }

    }

}

Next, we know that ClassView will have to bind to and display this property. Since the title of this post says to use a ListBox, that is what we will use.  ClassView’s definition will change to the following.

ClassView.xaml:

<Window x:Class=”ObjectDatabindingExample.ClassView”

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

    Title=”Object Data Binding Example” Height=”300″ Width=”300″>

    <Grid>

        <ListBox />

    </Grid>

</Window>

Okay, now that we know what visible object will be bound to ClassModel, let’s move forward by having the ClassView create an instance of ClassModel to which it will bind. Currently we do not have access to our project’s code from within ClassView’s xaml. To remedy this we have to add our project’s namespace in the opening “<Window>” tag with a namespace identifier.  I’m arbitrarily choosing to use “local” as the label to represent the project’s namespace.  Now that we have access to the project objects, ClassView can create an instance of ClassModel in its resource dictionary.  See below for changes.

ClassView.xaml:

<Window x:Class=”ObjectDatabindingExample.ClassView”

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

    xmlns:local=”clr-namespace:ObjectDatabindingExample”

    Title=”Object Data Binding Example” Height=”300″ Width=”300″>

   

    <Window.Resources>

        <local:ClassModel x:Key=”model” />

    </Window.Resources>

   

    <Grid>

        <ListBox />

    </Grid>

</Window>

Here, it is important to note a few things. When you create an object for use in a resource dictionary (as we have done with our ClassModel object) a key is required.  This requirement makes sense since we will later want to retrieve the object from the dictionary.

Moving forward, in order for ClassController to modify the correct ClassModel object, ClassView will have to give its instance of ClassModel to ClassController. For our purposes, this will be done on the window loaded event.  This is the first time we have to change the code behind in ClassView.  We have to add an event handler in the code behind to be called after the window loads.  See both definitions below.

ClassView.xaml:

<Window x:Class=”ObjectDatabindingExample.ClassView”

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

    xmlns:local=”clr-namespace:ObjectDatabindingExample”

    Title=”Object Data Binding Example” Height=”300″ Width=”300″ Loaded=”Window_Loaded”>

   

    <Window.Resources>

        <local:ClassModel x:Key=”model” />

    </Window.Resources>

   

    <Grid>

        <ListBox />

    </Grid>

</Window>

 

ClassView.xaml.cs:

using System.Windows;

 

namespace ObjectDatabindingExample

{

    public partial class ClassView : Window

    {

        public ClassView()

        {

            InitializeComponent();

        }

 

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

        }

    }

}

In ClassView.xaml.cs  Window_Loaded(object, RoutedEventArgs) is called after the window has loaded, and hopefully after the ClassModel instance has been created and added to the window’s dictionary. Next we have to implement this event by retrieving the instance of ClassModel from the resources dictionary and giving it to ClassControllerClassView has to have a way to give ClassController the ClassModel object, so we will implement a Initialize(ClassModel ) method on the controller that stores a reference to the given ClassModel instance. This initialize method will be called from ClassView’s Window_Loaded event handler.

ClassView.xaml.cs:

using System.Windows;

 

namespace ObjectDatabindingExample

{

    public partial class ClassView : Window

    {

        public ClassView()

        {

            InitializeComponent();

        }

 

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            try

            {

                ClassModel model = this.Resources[“model”] as ClassModel;

                this._controller.Initialize(model);

            }

            catch { /* Chomp, chomp! */ }

        }

 

        #region Private Members

 

        private ClassController _controller = new ClassController();

 

        #endregion

    }

}

ClassController.cs:

namespace ObjectDatabindingExample

{

    public class ClassController

    {

        public void Initialize(ClassModel model)

        {

            this._model = model;

        }

 

        #region Private Members

 

        private ClassModel _model;

 

        private readonly ClassInfo[] _data = new ClassInfo[] {

            new ClassInfo() { Name = “Calculus II” },

            new ClassInfo() { Name = “Physics” },

            new ClassInfo() { Name = “AI Algorithms and Design Considerations” },

            new ClassInfo() { Name = “Programming Patterns” },

            new ClassInfo() { Name = “Computer Networks” },

            new ClassInfo() { Name = “Building and Programming Robots” },

            new ClassInfo() { Name = “Distributed Systems” }

        };

 

        #endregion

    }

}

Okay, ClassController now has a reference to the same ClassModel object to which ClassView will bind.  Let us go ahead and bind the ListBox in ClassView to the ObservableCollection contained by the model instance.

ClassView.xaml:

<Window x:Class=”ObjectDatabindingExample.ClassView”

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

    xmlns:local=”clr-namespace:ObjectDatabindingExample”

    Title=”Object Data Binding Example” Height=”300″ Width=”300″ Loaded=”Window_Loaded”>

   

    <Window.Resources>

        <local:ClassModel x:Key=”model” />

    </Window.Resources>

   

    <Grid>

        <ListBox ItemsSource=”{Binding Classes, Source={StaticResource model}}” />

    </Grid>

</Window>

Since this is why we’re here, let’s dissect this statement for a moment.  The statement:

<ListBox ItemsSource=”{Binding Classes, Source={StaticResource model}}” />

 

We have a ListBox whose source is the result of “{Binding Classes, Source={StaticResource model}}”.  The first part of this (“{Binding Classes,…”) specifies that we want the ItemsSource property on the ListBox to be bound to the Classes property in the current DataContext.  In order for the binding statement to refer to the Classes property on the ClassModel instance we have in ClassView’s resource dictionary, we override the current DataContext by specifying the Source attribute in the binding statement to point to the resource dictionary key of the ClassModel instance, namely “model.” “{StaticResource model}” returns an item from the static resources dictionary that is associated with the key “model.”  The full statement sets up binding to the Classes property on the object in the resource dictionary whose key is “model.”

So, ClassView is now bound to the Classes property on an instance of ClassModel, and ClassController has a reference to that instance.  Let’s have the controller try this whole MVC/Databinding idea out by modifying the ClassModel instance in its Initialize method.  (We will simply set Classes property to a new ObservableCollection<ClassInfo> containing data from the controller.)

ClassController.cs:

using System.Collections.Generic;

using System.Collections.ObjectModel;

 

namespace ObjectDatabindingExample

{

    public class ClassController

    {

        public void Initialize(ClassModel model)

        {

            this._model = model;

 

            // The ObservableCollection’s constructor requires a List object. Because of this

            // we have to wrap the ClassInfo array in a List.

            this._model.Classes = new ObservableCollection<ClassInfo>(new List<ClassInfo>(this._data));

        }

 

        #region Private Members

 

        private ClassModel _model;

 

        private readonly ClassInfo[] _data = new ClassInfo[] {

            new ClassInfo() { Name = “Calculus II” },

            new ClassInfo() { Name = “Physics” },

            new ClassInfo() { Name = “AI Algorithms and Design Considerations” },

            new ClassInfo() { Name = “Programming Patterns” },

            new ClassInfo() { Name = “Computer Networks” },

            new ClassInfo() { Name = “Building and Programming Robots” },

            new ClassInfo() { Name = “Distributed Systems” }

        };

 

        #endregion

    }

}

So we have the data binding done, and the controller is updating the correct model instance, however, running the application shows that something is still wrong.  We don’t see any items in the ListBox.  What happened is that the ClassModel object didn’t tell ClassView about the controller changing its Classes property during the call to Initialize. To remedy this, ClassModel must implement the INotifyPropertyChanged interface which allows for ClassView to register for updates to the ClassModel instance.  When you setup data binding it appears that if the object being bound to implements this interface it is automatically used

ClassModel.cs:

using System.Collections.ObjectModel;

using System.ComponentModel;

 

namespace ObjectDatabindingExample

{

    public class ClassModel : INotifyPropertyChanged

    {

        public ObservableCollection<ClassInfo> Classes

        {

            get { return this._classes; }

            set

            {

                this._classes = value;

                this.sendPropertyChanged(“Classes”);

            }

        }

 

        #region INotifyPropertyChanged Members

 

        public event PropertyChangedEventHandler PropertyChanged;

 

        #endregion

 

        #region Private Members

 

        private void sendPropertyChanged(string property)

        {

            if (this.PropertyChanged != null)

            {

                this.PropertyChanged(this, new PropertyChangedEventArgs(property));

            }

        }

 

        private ObservableCollection<ClassInfo> _classes;

 

        #endregion

    }

}

Alright! Our objects are being shown in the ListBox!  But there is obviously a problem. The type of the object is being shown, not the data within.  This is okay except that I think we would rather see the data which distinguishes the objects from each other.

So we have a problem with the way these objects are being displayed.  Let’s change the way ClassView displays these ClassInfo objects by creating a DataTemplate for the ListBox to apply to its items.  For simplicity we will display each item by a Label whose content is bound to a Name property.  Changes to ClassView follows.

ClassView.xaml:

<Window x:Class=”ObjectDatabindingExample.ClassView”

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

    xmlns:local=”clr-namespace:ObjectDatabindingExample”

    Title=”Object Data Binding Example” Height=”300″ Width=”300″ Loaded=”Window_Loaded”>

 

    <Window.Resources>

        <local:ClassModel x:Key=”model” />

    </Window.Resources>

 

    <Grid>

       

        <ListBox ItemsSource=”{Binding Classes, Source={StaticResource model}}”>

           

            <ListBox.ItemTemplate>

               

                <DataTemplate>

                   

                    <Label Content=”{Binding Name}” />

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

    </Grid>

</Window>

This XAML is saying that we want to set the ListBox’s ItemTemplate to a DataTemplate which contains a Label whose Content is bound to the Name property of the item to which the template is being applied.  In our case this data template is being applied to each of the ClassInfo objects contained by the ObservableCollection<ClassInfo> Classes property of the ClassModel object.

A ListBox which has a DataTemplate defined for its items to correctly display ClassInfo objects

16 Comments »

  1. Phong said,

    Very informative.

  2. 301x said,

    What if i don’t want to use XAML code and only C# code, I can get to the part of binding data to the itemlist
    “itemlist.itemsource = list”

    but how can i select programatically wich data i want to be displayed

    Xaml:

    in c# how can i achieve this?

  3. Aloneball said,

    Very nice tutorial… good work.

    Nice breakup in small steps, and good explanations. And very relevant stuff covered.

    Thanks

  4. Frank said,

    There has to be a simpler way. I could simply code the loading of the listbox whenever necessary and do it in less code than you have here to describe this binding conept. It’s not saving any time or code.

    • Phong said,

      Frank,

      Of course there is always a simpler way, depending on what you’re trying to accomplish. If you just want to display the contents of an array inside a list box, then you can simply create an array of strings and set it as the list box’s items source. However, such an example wouldn’t be terribly useful.

      Designing your classes using INotifyPropertyChanged and other concepts described here allows your display to update instantly to reflect changes in the data source without any additional coding on your part, and this applies to any other property you might be binding.

      The relationship would of course apply in the other direction: if you were binding to eg. a text box, your data source could be updated immediately to reflect user modification.

  5. Mutia said,

    I am binding createddatetime with a textblock. The createddatetime appears in correct format in the cs part but after binding in xaml part, a fixed format is displayed irrespective of what is set in the cs part.Is there any way by which I can check and set the format according to the cultureinfo.currentculture during binding? Can you please help me out with this?

  6. Ruud said,

    Great tutorial,

    Did try to apply this to a datagrid. but doesn’t seem to work, my rows just don’t get filled. And your code example isn’t available anymore so can’t check if I missed anything extra. Was also wondering if with this example the data will automatically update if you add some edit method’s on your array in the controller. cause you don’t really show how that’s supposed to work.

  7. saju said,

    Good article…..keep it up.

  8. tommy tiang said,

    Good explaination. However, the source code is not available. Appreciate you can send over to me.

  9. Sig Villagomez said,

    Is the source still available for this post somewhere else?

    Thanks

  10. JulianaBooleana said,

    Very nice tutorial.
    I just made an adaptation of this tutorial to my project.
    Elements are being inserted and automatically updated in the view, so it seems to work… the problem when I remove the elements in my list. The list is empty but the view still shows the old items!
    What am I doing wrong?

    • Mike said,

      @Juliana
      It’s difficult to speculate what might be happening without an example. If you could supply a snippet, I’ll take a look at it.

  11. mehrad1362 said,

    Amazing article. I wanted something similar for MVVM but figured it out using this. Thanks heaps.

  12. Natalie said,

    Thank you SOOOO much fo rthis article! I am new to WPF and have struggled to find a clear, complete and informative document to help me get my head around the ocncepts. This was perfect! And there aren’t too many resources on binding dynamic data to a listbox, so again, this was perfect. Star tutorial! Thank you.

  13. t2014 said,

    Hey Mike, Do you read the comments? Download to source code doesn’t work.

    • Mike said,

      @t2014: My apologies. The original files have been lost over the years. I’ve rewritten it with Visual Studio 2012 Express and pushed a new repository to github. I figure they are a bit more reliable of file server than myself. =]


Leave a comment