Странное поведение при привязке к ListBox в WPF - PullRequest
0 голосов
/ 02 декабря 2010

Я заметил странное поведение при привязке массива к ListBox. Когда я добавляю элементы с одинаковым «именем», я не могу выбрать их во время выполнения - ListBox сходит с ума. Если я даю им уникальные «имена», это работает просто отлично. Может кто-нибудь объяснить, ПОЧЕМУ это происходит?

Вид:

<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>

Модель просмотра:

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 Ответ

2 голосов
/ 02 декабря 2010

Все элементы в WPF ListBox должны быть уникальными экземплярами. Строки с одинаковым постоянным значением не являются уникальными экземплярами из-за интернирования строк. Чтобы обойти это, вам нужно заключить элемент в более значимый объект, чем строка, например:

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

Теперь вы можете создавать экземпляры нескольких экземпляров DataItem и создавать шаблон ItemDataTemplate для отображения текста в виде TextBlock. Вы также можете переопределить DataItem ToString (), если хотите использовать рендеринг по умолчанию. Теперь вы можете иметь несколько экземпляров DataItem с одним и тем же текстом и без проблем.

Это ограничение может показаться немного странным, но оно упрощает логику, поскольку теперь SelectedItem имеет взаимно-однозначное соответствие с SelectedIndex для элементов в списке. Это также соответствует подходу WPF к визуализации данных, который направлен на списки значимых объектов, а не на списки простых строк.

...