在WPF中绑定到ListBox时的奇怪行为

在WPF中绑定到ListBox时的奇怪行为,wpf,data-binding,listbox,binding,Wpf,Data Binding,Listbox,Binding,在将数组绑定到列表框时,我注意到一些奇怪的行为。当我添加具有相同“名称”的项目时,我无法在运行时选择它们-列表框会变得疯狂。如果我给他们起一个独特的“名字”,效果很好。谁能解释一下为什么会这样 观点: <Window x:Class="ListBoxTest.ListBoxTestView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://sc

在将数组绑定到列表框时,我注意到一些奇怪的行为。当我添加具有相同“名称”的项目时,我无法在运行时选择它们-列表框会变得疯狂。如果我给他们起一个独特的“名字”,效果很好。谁能解释一下为什么会这样

观点:

<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");
        }
    }
}
使用System.Collections.Generic;
使用系统组件模型;
使用System.Windows.Input;
名称空间ListBoxTest
{
内部类ListBoxTestViewModel:INotifyPropertyChanged
{
私有列表realItems=新列表();
公共ListBoxTestViewModel()
{
realItems。添加(“项目A”);
realItems.添加(“B项”);
}
公共事件属性更改事件处理程序属性更改;
私有void OnPropertyChanged(字符串propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
公共字符串[]项
{
获取{return realtimes.ToArray();}
}
公共ICommand添加
{
//从Prism中删除命令
获取{返回新的DelegateCommand(DoAdd);}
}
私有整数x=1;
公共无效DoAdd()
{
var newItem=“Item”;
//取消注释以修复
//newItem+=“”+(x++)。ToString();
realtimes.Add(newItem);
不动产变更(“项目”);
}
}
}

WPF列表框中的所有项目都必须是唯一的实例。具有相同常量值的字符串不是唯一的实例,这是由于字符串内部的原因。要解决这个问题,您需要将项目封装在比字符串更有意义的对象中,例如:

public class DataItem 
{ 
    public string Text { get; set; } 
}
现在,您可以实例化多个DataItem实例并创建ItemDataTemplate以将文本呈现为TextBlock。如果要使用默认呈现,还可以重写DataItem ToString()。现在,您可以有多个具有相同文本且没有问题的DataItem实例


这个限制看起来有点奇怪,但它简化了逻辑,因为现在SelectedItem与列表中项目的SelectedIndex有一对一的对应关系。它还与WPF的数据可视化方法一致,后者倾向于有意义的对象列表,而不是普通字符串列表。

它实际上不是关于唯一实例(引用相等),而是关于逻辑相等(虚拟相等方法)。如果两个字符串具有相同的内容,那么即使它们是不同的引用,也会从列表框中获得奇怪的行为。但是,是的,将它们包装在不重写Equals的引用类型中应该可以解决问题。