0

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");
        }
    }
}

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

It's actually not about unique instances (reference equality), it's about logical equality (the virtual Equals method). If two strings have the same content, you'll get weird behavior from the ListBox even if they're different references. But yes, wrapping them in a reference type that doesn't override Equals should fix the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.