PrinceBilliard
PrinceBilliard

Reputation: 191

Items in ObservableCollection being duplicated

I have a WPF DataGrid bound to an ObservableCollection in my view model. I have context menu action to duplicate the row up or down, that is, insert a new row with the same content above or below the currently-selected row. This all works well and good, but the newly-inserted row seems to be a copy of the other one. Modifying one also modifies its duplicate. This isn't what I want; I want each row to be separate. Here is my code in the view model to duplicate the row downward:

    private void DuplicateDownward()
    {
        CPWrapper row = GetSelectedRow();
        if (row == null)
            return;

        Channels.Insert(SelectedRow + 1, new CPWrapper(row.InnerCP));
    }

Channels is an ObservableCollection<CPWrapper> (with a readonly backing, using only Clears and Inserts), and CPWrapper is a class that wraps around another object (not important). GetSelectedRow returns either the currently selected DataGrid row, or null.

As you can see, I'm inserting a new object from the existing row, and it's still acting like the same object. I even overrode some functions in CPWrapper like such:

public class CPWrapper
{
    private InnerObject cp;

    private static Random rand = new Random();

    private readonly int AntiCopy;

    public CPWrapper()
    {
        cp = new InnerObject();

        AntiCopy = rand.Next();
    }

    public CPWrapper(InnerObject arg)
    {
        cp = arg;

        AntiCopy = rand.Next();
    }

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

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

I was hoping that between GetHashCode from a random integer and Equals always returning false, the system would get the idea that they're not the same.

Any suggestions would be greatly appreciated.

Upvotes: 0

Views: 896

Answers (1)

Daneau
Daneau

Reputation: 1105

Adding to your InnerObject a copy constructor is the only solution for this. In C# object are referenced. Thus even if your wrapper "thinks" it is a different object the reference towards the "duplicate" points directly towards the "source object".

By doing so you will be sure you are not working with the same object. And remember that each object inside the inner object should have a copy constructor in order for this to work. Otherwise reference towards objects will stay the same.

Additional information. The override for the equals method should be return obj.AntiCopy == this.AntiCopy
otherwise even if you try to know if Wrapper1 == Wrapper1 it will be false. But if you do add the copy constructor the whole wrapper becomes useless in the current case

Upvotes: 1

Related Questions