Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make items in an ObservableCollection unique?

Tags:

c#

collections

I'm populating an observable collection with the following:

var customers = new ObservableCollection<Customer>();

foreach (
    var customer in
        collListItem.Select(
            item =>
            new Customer
                {
                    Persona = item["Persona"].ToString(),
                    CustomerName = item["Title"].ToString()
                }))
{
    customers.Add(customer);
}

Before I populate a WPF datagrid with the elements from this collection I'd like to make it a unique list of personas and customers (no duplicate rows).

I tried to use the following for this:

customers = customers.Distinct();

However I received the error:

Cannot convert source type 'System.Collections.Generic.IEnumerable to target type 'System.Collections.ObjectModel.ObservableCollection

Is there an equivalent for an ObservableCollection that I can use?

like image 604
Michael A Avatar asked Aug 18 '15 04:08

Michael A


People also ask

Why do we use ObservableCollection in C#?

An ObservableCollection is a dynamic collection of objects of a given type. Objects can be added, removed or be updated with an automatic notification of actions. When an object is added to or removed from an observable collection, the UI is automatically updated.

What is ObservableCollection in xamarin forms?

Represents a dynamic data collection that provides notifications when items get added or removed, or when the whole list is refreshed.


3 Answers

Because Distinct returns an IEnumerable<T>, which is not an ObservableCollection.

If you want to distinct ObservableCollection you should create it again like this:

customers = new ObservableCollection<Customer>(customers.Distinct());

Or, as variant, you can modify your query and distinct at once:

foreach (
var customer in
    collListItem.Select(
        item =>
        new Customer
            {
                Persona = item["Persona"].ToString(),
                CustomerName = item["Title"].ToString()
            }).Distinct())
{
    customers.Add(customer);
}
like image 159
Artem Kulikov Avatar answered Oct 17 '22 02:10

Artem Kulikov


Well this is an old question but I am just facing the same issue and I think I found an alternative way to do what the OP is attempting. First of all I think we are facing here an XY problem. The OP wants to hold an ObservableCollections with unique items, now, both answers existing answers solve the problem in a way, but I think this way is not the best.

This should be the responsibility of the data structure we are using. If that data structure does not exist let's create it!

The requirement is quite clear: To have an ObservableCollection with unique items. The way I foudn was to inherit from ObservableCollection and provide custom logic to do this:

public class ObservableUniqueCollection <T> : ObservableCollection<T>
{
    private readonly HashSet<T> _hashSet;

    public ObservableUniqueCollection() : this(EqualityComparer<T>.Default) { }

    public ObservableUniqueCollection(IEqualityComparer<T> equalityComparer) => _hashSet = new HashSet<T>(equalityComparer);

    public void AddRange(IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            InsertItem(Count, item);
        }
    }

    protected override void InsertItem(int index, T item)
    {
        if (_hashSet.Add(item))
        {
            base.InsertItem(index, item);
        }
    }

    protected override void ClearItems()
    {
        base.ClearItems();
        _hashSet.Clear();
    }

    protected override void RemoveItem(int index)
    {
        var item = this [index];
        _hashSet.Remove(item);
        base.RemoveItem(index);
    }

    protected override void SetItem(int index, T item)
    {
        if (_hashSet.Add(item))
        {
            var oldItem = this[index];
            _hashSet.Remove(oldItem);
            base.SetItem(index, item);
        }
    }
}

So now you don't have to worry about having repeated items in your collection (as long as your type implements IEquatable or you provide an IEqualityComparer)

like image 41
taquion Avatar answered Oct 17 '22 01:10

taquion


This will work without having to implement your own compare on Customer

foreach (var customer in collListItem.Select(
            item => 
                new {
                    Persona = item["Persona"].ToString(),
                    CustomerName = item["Title"].ToString()
                }).Distinct()
                .Select(r => new Customer { Persona = r.Persona,
                                            CustomerName = r.CustomerName }))
{
    customers.Add(customer);
}
like image 2
Rob Avatar answered Oct 17 '22 03:10

Rob