#1,016 – Displaying a Collection of Items in a WrapPanel

You can use data binding to bind a collection of items to a WrapPanel by using the WrapPanel as the ItemsPanel for a simple ItemsControl.  (You could do the same thing with a ListBox).

In the example below, we bind to a collection of Actor objects and set the DataTemplate of our ItemsControl to just display the image of each actor.  The ItemsControl will resize to fit the containing window (via the StackPanel) and the WrapPanel will manage changing the layout of the images as the window size changes.

    <ItemsControl ItemsSource="{Binding ActorList}" Margin="20">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding Image}" Height="100"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

1016-001
1016-002
1016-003

#1,011 – ComboBox Data Binding Basics, Part III

To display the items in a ComboBox using something more than a simple string, you set the ItemTemplate of the ComboBox to define the layout of each item.  When you set the ItemTemplate, you don’t set the DisplayMemberPath property.  DisplayMemberPath defines the template for each item in the ComboBox to be a TextBlock that displays a single string.

Below, we set an item template for a ComboBox that binds to a collection of Actor objects so that we display an image and some information about the actor, for each item.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  SelectedItem="{Binding SelectedActor}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Image}" Height="100"/>
                        <StackPanel Margin="10,0">
                            <TextBlock Text="{Binding FullName}" FontWeight="Bold" />
                            <TextBlock Text="{Binding Dates}"/>
                            <TextBlock Text="{Binding KnownFor}" FontStyle="Italic"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <Label Content="{Binding SelectedActor.NameAndDates}"/>

As we select an item, notice that the ComboBox changes size, so that the surface can show the entire item.

1011-001

1011-002

#1,010 – ComboBox Data Binding Basics, Part II

When using data binding, you specify the collection of items to fill the ComboBox by setting the ItemsSource property.

You can also bind the currently selected item in the ComboBox to an instance of an object in code.  You do this by binding the SelectedItem property to a property in your code that represents an instance of the appropriate type.  When the user selects an item in the ComboBox, the corresponding object is updated to refer to the selected object.

Assume that we have the following in our code behind:

  • Actor class, representing an actor
  • ActorList property, which is an ObservableCollection<Actor>
  • SelectedActor property, of type Actor

In the example below, we bind the ComboBox to the list of actors and the currently selected actor to the SelectedActor property.  As we select an actor, the Label updates, since it also binds to SelectedActor.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  DisplayMemberPath="FullName"
                  SelectedItem="{Binding SelectedActor}"/>
        <Label Content="{Binding SelectedActor.NameAndDates}"/>

1010-001
1010-002

#1,009 – ComboBox Data Binding Basics, Part I

As with a ListBox, you can use data binding to load and manage the items displayed in a ComboBox control.

You set the ItemsSource property of the ComboBox to a collection that implements the IEnumerable interface.  The collection bound to can contain any type of object.

If you want the ComboBox to display simple strings, you can set the DisplayMemberPath property to the string-typed property of a bound object  that should be used to get the display string for each item.

        <ComboBox ItemsSource="{Binding ActorList}" Margin="20"
                  DisplayMemberPath="FullName"/>

1009-001

#976 – SelectedItem Binding on an ItemsControl is Two-Way

When you use data binding to associate a property in your data context to the currently selected item in an ItemsControl (e.g. a ListBox), the data binding is by default two-way.  That is:

  • When the user selects a new item in the list, the value of the bound property changes
  • If the value of the bound property changes, the selection in the list changes

Suppose that we bind the ItemsSource of a ListBox to a collection of Actor objects and that we bind the SelectedItem property of the ListBox to a SelectedActor property in our data context (of type Actor).

When the user selects an item, the value of the SelectedActor property changes.  (Below, the labels are bound to sub-properties of SelectedActor).

976-003

If we instead change the value of SelectedActor (e.g. in code-behind after clicking a button), the currently selected item in the ListBox will change.

976-004

#968 – ListBox Data Binding Basics, part V

If you want to display the items in a ListBox using something more than a simple string, you can set the ItemTemplate of the ListBox and define the exact layout of each item.  When you set the ItemTemplate, you don’t set the DisplayMemberPath property.  DisplayMemberPath simple defines the template for each item in the ListBox to be a TextBlock that displays a single string.

In the example below, we set an item template for a ListBox that binds to a collection of Actor objects so that we display an image and some information about the actor, for each item.

        <ListBox Margin="15" Width="250" Height="250"
                 ItemsSource="{Binding ActorList}"
                 SelectedItem="{Binding SelectedActor}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Image}" Height="80"/>
                        <StackPanel Margin="5">
                            <TextBlock Text="{Binding FullName}" FontSize="12" FontWeight="Bold"/>
                            <TextBlock Text="{Binding Dates}"/>
                            <TextBlock Text="{Binding KnownFor}" Margin="0,5,0,0" FontStyle="Italic"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

968-001

#967 – ListBox Data Binding Basics, part IV

In the earlier posts, we created an Actor class and then populated a list with a series of Actor objects.  We can now bind a ListBox to this list using its ItemsSource property.

    <StackPanel>
        <ListBox Margin="15" Width="250" Height="250"
                 ItemsSource="{Binding ActorList}"
                 DisplayMemberPath="NameAndDates"
                 SelectedItem="{Binding SelectedActor}"/>
        <Label Margin="10,0" Content="{Binding SelectedActor.KnownFor}"/>
    </StackPanel>

The ItemsSource property indicates that we want the ListBox filled with elements from our ActorList property, which is a collection of Actor objects.

The DisplayMemberPath property indicates that each entry in the list should be rendered as a string using the Actor.NameAndDates property.

The SelectedItem property indicates that when a user selects an item, our SelectedActor property should be set to refer to the selected Actor instance.  We demonstrate that by binding a Label element to a property of that selected actor.

967-001

#966 – ListBox Data Binding Basics, part III

Assume that we want to use a ListBox to display a list of actors and that we have an Actor type to store all the information for a single actor.

Our next step is to create a collection of Actor instances that we’ll then be able to bind to.  Below is the code-behind for a simple WPF application that creates a collection of Actor instances and stores them in an ActorList property.  We also set up a SelectedActor property that will use data binding to reflect the actor that the user has currently selected.

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            this.InitializeComponent();
            this.DataContext = this;

            ActorList = new ObservableCollection<Actor>
            {
                new Actor("Ginger Rogers", 1911, 1995, "Kitty Foyle",
                    new Uri("ActressImages/GingerRogers.jpg", UriKind.Relative)),
                new Actor("Joan Fontaine", 1917, null, "Suspicion",
                    new Uri("ActressImages/JoanFontaine.jpg", UriKind.Relative)),
                new Actor("Greer Garson", 1904, 1996, "Mrs. Miniver",
                    new Uri("ActressImages/GreerGarson.jpg", UriKind.Relative)),
                new Actor("Jennifer Jones", 1919, 2009, "The Song of Bernadette",
                    new Uri("ActressImages/JenniferJones.jpg", UriKind.Relative)),
                new Actor("Ingrid Bergman", 1915, 1982, "Gaslight",
                    new Uri("ActressImages/IngridBergman.jpg", UriKind.Relative)),
                new Actor("Joan Crawford", 1904, 1977, "Mildred Pierce",
                    new Uri("ActressImages/JoanCrawford.jpg", UriKind.Relative)),
                new Actor("Olivia de Havilland", 1916, null, "To Each His Own",
                    new Uri("ActressImages/OliviaDeHavilland.jpg", UriKind.Relative)),
                new Actor("Loretta Young", 1913, 2000, "The Farmer's Daughter",
                    new Uri("ActressImages/LorettaYoung.jpg", UriKind.Relative)),
                new Actor("Jane Wyman", 1917, 2007, "Johnny Belinda",
                    new Uri("ActressImages/JaneWyman.jpg", UriKind.Relative)),
                new Actor("Judy Holliday", 1921, 1965, "Born Yesterday",
                    new Uri("ActressImages/JudyHolliday.jpg", UriKind.Relative))
            };
        }

        private ObservableCollection<Actor> actorList;
        public ObservableCollection<Actor> ActorList
        {
            get { return actorList; }
            set
            {
                if (value != actorList)
                {
                    actorList = value;
                    RaisePropertyChanged("ActorList");
                }
            }
        }

        private Actor selectedActor;
        public Actor SelectedActor
        {
            get { return selectedActor; }
            set
            {
                if (value != selectedActor)
                {
                    selectedActor = value;
                    RaisePropertyChanged("SelectedActor");
                }
            }
        }

        // INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

#965 – ListBox Data Binding Basics, part II

Assume that we want to use a ListBox to display a list of actors.  We can start by creating an Actor type that stores various information about an actor.  We want the class to implement the INotifyPropertyChanged interface, so that data binding client are notified of changes to any properties.

Full code for Actor.cs is shown below.  Note that when we change FullName, BirthYear or DeathYear properties, we also flag the derived NameAndDates property as potentially changed.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace WpfApplication2
{
    public class Actor : INotifyPropertyChanged
    {
        public Actor()
        {
        }

        public Actor(string fullName, int? birthYear, int? deathYear, string knownFor, Uri image)
        {
            FullName = fullName;
            BirthYear = birthYear;
            DeathYear = deathYear;
            KnownFor = knownFor;
            Image = image;
        }

        private string fullName;
        public string FullName
        {
            get { return fullName; }
            set
            {
                fullName = value;
                RaisePropertyChanged("FullName");
                RaisePropertyChanged("NameAndDates");
            }
        }

        private int? birthYear;
        public int? BirthYear
        {
            get { return birthYear; }
            set
            {
                birthYear = value;
                RaisePropertyChanged("BirthYear");
                RaisePropertyChanged("NameAndDates");
            }
        }

        private int? deathYear;
        public int? DeathYear
        {
            get { return deathYear; }
            set
            {
                deathYear = value;
                RaisePropertyChanged("DeathYear");
                RaisePropertyChanged("NameAndDates");
            }
        }

        private string knownFor;
        public string KnownFor
        {
            get { return knownFor; }
            set
            {
                knownFor = value;
                RaisePropertyChanged("KnownFor");
            }
        }

        private Uri image;
        public Uri Image
        {
            get { return image; }
            set
            {
                image = value;
                RaisePropertyChanged("Image");
            }
        }

        public string NameAndDates
        {
            get
            {
                string result = FullName;

                if (BirthYear.HasValue)
                {
                    if (DeathYear.HasValue)
                        result = result + string.Format(" ({0}-{1})", BirthYear.Value, DeathYear.Value);
                    else
                        result = result + string.Format(" ({0}- )", BirthYear.Value);
                }

                return result;
            }
        }

        // INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

#964 – ListBox Data Binding Basics, Part I

You can use data binding to load and manage the items displayed in a ListBox control.

You bind the ItemsSource property of the ListBox to a collection that implements the IEnumerable interface.  The collection bound to can contain any type of object.

If the ListBox is displaying simple strings, you can set the DisplayMemberPath property to the string-typed property of a bound object  that should be used to get the display string for each item.

You can also use binding to bind the SelectedItem property of the ListBox to a property whose type matches the types in the collection that ItemsSource binds to.  When the user selects an item in the ListBox, the corresponding property is updated to refer to the correct item.  And if the property bound to is changed from code-behind, the selected item in the ListBox changes.

Next time: Code sample for all of this.