Arian Motamedi
Arian Motamedi

Reputation: 7413

Binding to collections in WPF

So I finally decided to move from WinForms to WPF, and I'm having quite an interesting journey. I have a simple application in which I bind an ObservableCollection to a ListBox.

I have an Animal entity:

namespace MyTestApp
{
    public class Animal
    {
        public string animalName;
        public string species;

        public Animal()
        {
        }

        public string AnimalName { get { return animalName; } set { animalName = value; } }
        public string Species { get { return species; } set { species = value; } }
    }
}

And an AnimalList entity:

namespace MyTestApp
{
    public class AnimalList : ObservableCollection<Animal>
    {
        public AnimalList() : base()
        {
        }
    }
}

And finally here's my main window:

<Window x:Class="MyTestApp.Window3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyTestApp"
    Title="Window3" Height="478" Width="563">

<Window.Resources>
    <local:AnimalList x:Key="animalList">
        <local:Animal AnimalName="Dog" Species="Dog"/>
        <local:Animal AnimalName="Wolf" Species="Dog"/>
        <local:Animal AnimalName="Cat" Species="Cat"/>
    </local:AnimalList>    
</Window.Resources>

<Grid>
    <StackPanel Orientation="Vertical" Margin="10,0,0,0">
        <TextBlock FontWeight="ExtraBold">List of Animals</TextBlock>
        <ListBox ItemsSource="{Binding Source={StaticResource animalList}, Path=AnimalName}"></ListBox>
    </StackPanel>
</Grid>

Now when I run the application, I see the listbox populated with three items: "D", "o", and "g" instead of "Dog", "Wolf", and "Cat":

enter image description here

I have a strong feeling that I'm doing something stupid somewhere (AnimalList constructor maybe?) but I can't figure out what it is. Any help is appreciated.

Upvotes: 0

Views: 233

Answers (2)

Steven Magana-Zook
Steven Magana-Zook

Reputation: 2759

You need to set the DisplayMemberPath (as opposed to the Path property in the binding).

<Grid>
    <StackPanel Orientation="Vertical" Margin="10,0,0,0">
        <TextBlock FontWeight="ExtraBold">List of Animals</TextBlock>
        <ListBox ItemsSource="{Binding Source={StaticResource animalList}}" DisplayMemberPath="AnimalName"></ListBox>
    </StackPanel>
</Grid>

Since you are binding to a list of Animal objects, DisplayMemberPath specifies the name of the property in the Animal class that you want to show up as a list item.

If the property is itself an object, you can use dot notation to specify the full path to the property you want displayed ie..

<ListBox ItemsSource="{Binding Source={StaticResource animalList}}" DisplayMemberPath="PropertyInAnimalClass.PropertyInTheChildObject.PropertyToDisplay" />

Upvotes: 1

Kenneth
Kenneth

Reputation: 28737

You're binding your listbox to the animalname. Instead you should bind your listbox to your collection:

<ListBox ItemsSource="{Binding Source={StaticResource animalList}}"></ListBox>

Notice that I've removed the path=AnimalName from the binding.

Now you will see the class name, since the ListBox doesn't know how to display an Animal and therefore it calls its ToString-method.

You can solve this by giving it an ItemTemplate like so:

<ListBox ItemsSource="{Binding Source={StaticResource animalList}}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>    
                <TextBlock Text="{Binding AnimalName}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Inside the itemtemplate your DataContext is an instance of Animaland you can then bind to the properties on that instance. In my example I have bound the AnimalName, but you basically construct any template you want using normal XAML-controls and binding to the different properties of your bound object.

Upvotes: 0

Related Questions