4

我将 Horizo​​ntal ItemsControl 转换为 Listbox,以便能够选择单个项目,但发现选择已损坏。花了一些时间来提炼出有问题的部分。

Books = new[] { new Book{Id=1, Name="Book1"},
                                 new Book{Id=2, Name="Book2"},
                                 new Book{Id=3, Name="Book3"},
                                 new Book{Id=4, Name="Book4"},
                                 new Book{Id=3, Name="Book3"},
            };

            <DataTemplate DataType="{x:Type WPF_Sandbox:Book}">
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>

<ListBox ItemsSource="{Binding Books}"/>

如果 Book 是一个结构,如果您选择的项目在列表中具有等效结构,则列表框选择(默认模式:单一)会出错。例如书 3

如果 Book 变成一个类(具有非值类型语义),则选择是固定的。

选择(到目前为止,不喜欢其中任何一个):

  • 我选择 structs 是因为它是一个小型数据结构,并且值类型语义在比较 2 个实例是否相等时很有用。将其更改为类会导致我失去值类型语义。我不能再使用默认的 Equals 或覆盖它以进行成员比较。
  • 添加一个独特的 Book 属性,纯粹是为了让列表框选择起作用(例如索引)。
  • 消除重复.. 不可能。

WPF 列表框:选择问题:声明列表框正在设置 SelectedItem,并且在为此更新 UI 时,它只是点亮列表中的所有项目Equal(SelectedItem)。不知道为什么.. 突出 SelectedIndex 会使这个问题消失;也许我错过了一些东西。 即使在 SelectionMode="Single" 中,ListBox 也会选择许多项目:当列表项目是字符串时显示相同的问题(值类型语义)

4

4 回答 4

3

我不清楚为什么您的列表中有重复项,如果它们完全相同(即,如果重复项具有所有相同的内容并从 Equals 返回 true)。您将无法判断用户选择了哪些重复项。ListBox 也不会,这可能就是您遇到问题的原因。

也许,您可以将每个结构包装在一个类中,而不是直接绑定到结构集合?只需定义一个包含 Book 结构的 BookWrapper 类,并绑定到 BookWrapper 集合而不是 Books 集合。您解决了 WPF 无法区分实例的问题,但您的其余代码可以继续享受结构的好处。

于 2010-11-22T04:59:33.400 回答
3

为什么不简单地使用更好的集合类作为数据源来解决问题

var collection = new[]
 {
     new Book {Id = 1, Name = "Book1"},
     new Book {Id = 2, Name = "Book2"},
     new Book {Id = 3, Name = "Book3"},
     new Book {Id = 4, Name = "Book4"},
     new Book {Id = 3, Name = "Book3"},
 };
 var Books = collection.ToDictionary(b => Guid.NewGuid(), b => b);
 DataContext = Books;

这将是您的 DataTemplate

<ListBox ItemsSource="{Binding}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Value.Name}"/>
    </DataTemplate>
  </ListBox.ItemTemplate>
于 2010-11-18T13:53:09.800 回答
0

加里克斯

也许更简单一些?

public class StructListItem<T> where T : struct
{
    public T Item { get; private set; }
    public readonly Guid Id = Guid.NewGuid();
    public StructListItem(T item)
    {
        Item = item;
    }

    public static IEnumerable<StructListItem<U>> 
        GetStructList<U>(IEnumerable<U> originalList) where U : struct
    {
        return originalList.Select(i => new StructListItem<U>(i));
    }
}
于 2010-11-19T08:41:18.127 回答
0

感谢 Dean Chalk 的想法。

我对其进行了扩展,以便更容易使用其他结构

这个想法是使用转换器将原始结构集合转换为自定义集合,然后覆盖等于以与 Guid ID 进行比较。你还有原来的订单

public class StructListItem
{
    private Guid _id = Guid.NewGuid();
    public Guid ID
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
        }
    }

    private object _core = default(object);
    public object Core
    {
        get
        {
            return _core;
        }
        set
        {
            _core = value;
        }
    }

    public StructListItem(object core)
    {
        Core = core;
    }

    public override bool Equals(object obj)
    {
        return ID.Equals(obj);
    }

    public override int GetHashCode()
    {
        return ID.GetHashCode();
    }
}

public class StructToCollConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is IEnumerable)
        {
            List<StructListItem> _ret = new List<StructListItem>();
            if (value != null)
            {
                IEnumerator i = ((IEnumerable)value).GetEnumerator();
                while (i.MoveNext())
                {
                    _ret.Add(new StructListItem(i.Current));
                }
            }
            return _ret.ToArray();
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

    <ListBox ItemsSource="{Binding Books, Converter={StaticResource converter}}" SelectionMode="Single">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Core.Name}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>

    </ListBox>
于 2010-11-19T02:21:16.323 回答