Strange behaviour when binding to ListBox in WPF

I noticed some strange behaviour when binding an array to a ListBox. When I add items with the same "name", I can't select them in runtime - the ListBox goes crazy. If I give them unique "names", it works just fine. Could anyone please explain WHY is this happening?

The View:

<Window x:Class="ListBoxTest.ListBoxTestView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ListBoxTest"
        Title="ListBoxTestView" Height="300" Width="300">
    <Window.Resources>
        <local:ListBoxTestViewModel x:Key="Model" />
    </Window.Resources>
    <Grid DataContext="{StaticResource ResourceKey=Model}">
        <ListBox ItemsSource="{Binding Items}" Margin="0,0,0,70" />
        <Button Command="{Binding Path=Add}"  Content="Add" Margin="74,208,78,24" />
    </Grid>
</Window>

The View Model:

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Input;

namespace ListBoxTest
{
    internal class ListBoxTestViewModel : INotifyPropertyChanged
    {
        private List<string> realItems = new List<string>();

        public ListBoxTestViewModel()
        {
            realItems.Add("Item A");
            realItems.Add("Item B");
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public string[] Items
        {
            get { return realItems.ToArray(); }
        }

        public ICommand Add
        {
            // DelegateCommand from Prism
            get { return new DelegateCommand(DoAdd); }
        }

        private int x = 1;
        public void DoAdd()
        {
            var newItem = "Item";
            // Uncomment to fix
            //newItem += " " + (x++).ToString();
            realItems.Add(newItem);
            OnPropertyChanged("Items");
        }
    }
}

Answers


All items in a WPF ListBox must be unique instances. Strings that have the same constant value are not unique instances due to string Interning. To get around this, you need to encapsulate the item in a more meaningful object than a String, such as:

public class DataItem 
{ 
    public string Text { get; set; } 
}

Now you can instantiate multiple DataItem instances and create an ItemDataTemplate to render the Text as a TextBlock. You can also override the DataItem ToString() if you want to use the default rendering. You can now have multiple DataItem instances with the same Text and no problems.

This limitation may seem a bit strange, but it simplifies the logic, as now SelectedItem has a one-to-one correspondence with SelectedIndex for items in the list. It is also in line with the WPF approach to data visualization, which tends toward lists of meaningful objects as opposed to lists of plain strings.


Need Your Help

Django multiple profiles using auth.User. Standard student teacher example

django relational-database

Is it correct way to create 2 profiles in django? I want student to have access to his teachers, and teacher to his students as well. I mean if I log in as a student, I want to browse exactly teach...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.