Radinator Radinator - 2 months ago 16
C# Question

C# WPF Datbinding - Why does WPF display the single letter instead of the content of a list

I'm new to WPF so I tried some tutorials. Now in my second project there is something that drives me crazy...

Here is the C# code:

using System.Windows;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace WpfDataBindingTest1
{
public partial class MainWindow : Window
{
private ICollection<TestClass> testClassCollection;
public ICollection<TestClass> TestClassCollection
{
get { return this.testClassCollection; }
set { if (this.testClassCollection != value) { this.testClassCollection = value; } }
}
public MainWindow()
{
InitializeComponent();

this.testClassCollection = new ObservableCollection<TestClass>()
{
new TestClass() {ID = 1, Name = "Name1" },
new TestClass() {ID = 2, Name = "Name2" },
new TestClass() {ID = 3, Name = "Name3" }
};
}
}

public class TestClass
{
public int ID { get; set; }
public string Name { get; set; }
}
}


Here is the XAML Code:

<Window x:Class="WpfDataBindingTest1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfDataBindingTest1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox
x:Name="lbTestClassItems"
ItemsSource="{Binding Source=TestClassCollection}">

</ListBox>
</Grid>
</Window>


So when compiling and running this, I only get displayed each letter of the Word "TestClassCollection" in a new line in the listbox defined in the XAML file.

When adding
DisplayMemberPath="ID"
to the definition if the listbox, there is nothing displayed.

After some search I found this: why is it displaying class name instead of property?

But this didn't helped.

Edit: Mysteriously if I do it via code (set itemsource and DisplayMemberPath), the correct data is displayed. But if I do it via XAML, see above

Thanks in advance!

Answer

You need to use Path instead of Source otherwise you're binding to string TestClassCollection hence your one letter per item. Ideally, if your item is a complex object, you would also either set DisplayMemberPath or use ItemTemplate

<ListBox 
    x:Name="lbTestClassItems" 
    ItemsSource="{Binding Path=TestClassCollection}" 
    DisplayMemberPath="Name"/>

Another problem is that you don't set DataContext anywhere. All binding work in binding context.

public MainWindow()
{
    InitializeComponent();        
    this.testClassCollection = ...;
    this.DataContext = this;
}

You need to do it in this other because your MainWindow does not implement INotifyPropertyChanged interface and TestClassCollection property does not raise PropertyChanged event. After that you can add/remove to TestClassCollection and it should be picked up by UI because ObservableCollection<T> implements INotifyCollectionChanged interface