Selection bug for listbox where the list items are value types / structs and contain duplicates?

前端 未结 4 1946
耶瑟儿~
耶瑟儿~ 2020-12-19 16:04

I turned an Horizontal ItemsControl to a Listbox so that I am able to select individual items but found that the selection was broken. Took some time to distill out the prob

相关标签:
4条回答
  • 2020-12-19 16:45

    I'm not clear on why you have duplicates in your list, if they're absolutely identical (i.e., if duplicates have all the same content and return true from Equals). You won't have any way to tell which of the duplicates the user has selected. Neither will the ListBox, which is probably why you're having problems.

    Maybe, instead of binding directly to a collection of structs, you could wrap each struct in a class? Just define a BookWrapper class that contains a Book struct, and bind to a collection of BookWrappers instead of a collection of Books. You fix the problem of WPF not being able to tell the instances apart, but the rest of your code could continue to have the benefits of a struct.

    0 讨论(0)
  • 2020-12-19 16:48

    Garyx

    Something a bit simpler maybe ?

    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));
        }
    }
    
    0 讨论(0)
  • 2020-12-19 16:49

    Why not simply use a better collection class as your datasource to overcome the problem

    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;
    

    And this will be your DataTemplate

    <ListBox ItemsSource="{Binding}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Value.Name}"/>
        </DataTemplate>
      </ListBox.ItemTemplate>
    
    0 讨论(0)
  • 2020-12-19 16:54

    Thanks to Dean Chalk for his idea.

    I extend it so that it is easier to user for other structs

    The idea is to use a converter to cast the original struct collection to a custom collection, which in turn override the equal to compare with Guid ID. You still has the original order

    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>
    
    0 讨论(0)
提交回复
热议问题