firstly sorry for maybe not the best title, I didn't know how to express it better. This also means I could've missed similar answered questions. Feel free to suggest a better one title for the others :)
My question is pretty simple. I have derived collection limited to my object, it looks like this:
public sealed class TrajectoryCollection<T> : ObservableCollection<T> where T : TrajectoryPoint
{
public string FileName { get; set; }
public void AddPointUnder(T selectedPoint)
{
var newPoint = (TrajectoryPoint)selectedPoint.Clone();
var nextIndex = Items.IndexOf(selectedPoint) + 1;
newPoint.SetPosition(PositionBetween(selectedPoint, Items.ElementAt(nextIndex)));
Items.Insert(nextIndex, (T)newPoint);
RecalculatePointIndexes();
}
public void RemovePoint(T item)
{
Remove(item);
RecalculatePointIndexes();
}
private void RecalculatePointIndexes()
{
for (int i = 0; i < Count; i++)
{
Items.ElementAt(i).Number = i + 1;
}
}
private Point3D PositionBetween(Point3D first, Point3D second)
{
return new Point3D(Math.Round((first.X + second.X) / 2, 3), Math.Round((first.Y + second.Y) / 2, 3), Math.Round((first.Z + second.Z) / 2, 3));
}
}
and in my ViewModel I have this (Trajectory is bound to ListView itemsource):
public TrajectoryCollection<TrajectoryPoint> Trajectory
{
get => _trajectory;
set => SetProperty(ref _trajectory, value);
}
public TrajectoryPoint SelectedPoint
{
get => _selectedPoint;
set => SetProperty(ref _selectedPoint, value);
}
private void RemovePointFromTrajectoryExecute()
{
var selectedIndex = Trajectory.IndexOf(SelectedPoint);
Trajectory.RemovePoint(SelectedPoint);
SelectedPoint = Trajectory.ElementAt(selectedIndex);
RefreshViewport();
}
private void AddPointToTrajectoryExecute()
{
var selectedIndex = Trajectory.IndexOf(SelectedPoint);
Trajectory.AddPointUnder(SelectedPoint);
SelectedPoint = Trajectory.ElementAt(selectedIndex + 1);
RefreshViewport();
}
private void RefreshViewport()
{
RaisePropertyChanged("Trajectory");
RaisePropertyChanged("SelectedPoint");
}
Removing point works but adding doesn't. After adding one point, it IS added to that collection (I have verified it), but ListView won't show it - it behaves like it skips that added line (so it shows for example items 1,2,3,5,6...) and when I scroll down, it throws an exception
System.InvalidOperationException: 'An ItemsControl is inconsistent with its items source.
BUT. When I move that code from derived collection to my ViewModel, so it looks like this:
private void AddPointToTrajectoryExecute()
{
var newPoint = (TrajectoryPointModel)SelectedPoint.Clone();
var nextIndex = Trajectory.IndexOf(SelectedPoint) + 1;
//new Point3D is PositionBetween
newPoint.SetPosition(new Point3D(Math.Round((SelectedPoint.X + Trajectory.ElementAt(nextIndex).X) / 2, 3), Math.Round((SelectedPoint.Y + Trajectory.ElementAt(nextIndex).Y) / 2, 3), Math.Round((SelectedPoint.Z + Trajectory.ElementAt(nextIndex).Z) / 2, 3)));
Trajectory.Insert(nextIndex, newPoint);
RefreshViewport();
}
it works as it is supposed to and without any exceptions!
Could please anyone explain why this is happening? And what can I do to make working my Collection.AddPointUnder() method?
Thank you in advance!
I think the problem is as follows: In your add you are inserting in the underlying Items
collection. While the remove happens directly on the ObservableCollection
. Use Insert
or InsertItem
on the ObservableCollection
and it should update your view just fine. This is because the Items
collection of the ObservableCollection
is not observable.