Browse Source

Fix DevTools.

And add test to make sure it doesn't happen again.
pull/39/head
Steven Kirk 11 years ago
parent
commit
f3e362dddb
  1. 222
      Perspex.Base/Collections/PerspexReadOnlyListView.cs
  2. 2
      Perspex.Base/Collections/SingleItemPerspexList.cs
  3. 13
      Perspex.Controls/ItemsControl.cs
  4. 20
      Tests/Perspex.Controls.UnitTests/ItemsControlTests.cs

222
Perspex.Base/Collections/PerspexReadOnlyListView.cs

@ -13,29 +13,208 @@ namespace Perspex.Collections
using System.ComponentModel;
using System.Linq;
public class PerspexReadOnlyListView<T> : IReadOnlyPerspexList<T>, IDisposable
{
private IReadOnlyPerspexList<T> source;
public PerspexReadOnlyListView()
: this(null)
{
}
public PerspexReadOnlyListView(IReadOnlyPerspexList<T> source)
{
this.source = source;
if (source != null)
{
this.source.CollectionChanged += this.SourceCollectionChanged;
}
}
public T this[int index]
{
get { return this.source[index]; }
}
public int Count
{
get { return this.source.Count; }
}
public IReadOnlyPerspexList<T> Source
{
get
{
return this.source;
}
set
{
if (this.source != null)
{
this.source.CollectionChanged -= this.SourceCollectionChanged;
if (this.CollectionChanged != null)
{
var ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove,
this.source,
0);
this.CollectionChanged(this, ev);
}
}
this.source = value;
if (this.source != null)
{
this.source.CollectionChanged += this.SourceCollectionChanged;
if (this.CollectionChanged != null)
{
var ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
this.source,
0);
this.CollectionChanged(this, ev);
}
}
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
public void Dispose()
{
this.source.CollectionChanged -= this.SourceCollectionChanged;
}
public IEnumerator<T> GetEnumerator()
{
return this.source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
private void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (this.CollectionChanged != null)
{
NotifyCollectionChangedEventArgs ev;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
e.NewItems,
e.NewStartingIndex);
break;
case NotifyCollectionChangedAction.Remove:
ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove,
e.OldItems,
e.NewStartingIndex);
break;
case NotifyCollectionChangedAction.Replace:
ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Replace,
e.NewItems,
e.OldItems,
e.OldStartingIndex);
break;
default:
throw new NotSupportedException("Action not yet implemented.");
}
this.CollectionChanged(this, ev);
}
}
}
public class PerspexReadOnlyListView<TIn, TOut> : IReadOnlyPerspexList<TOut>, IDisposable
{
private IReadOnlyPerspexList<TIn> inner;
private IReadOnlyPerspexList<TIn> source;
private Func<TIn, TOut> convert;
public PerspexReadOnlyListView(
IReadOnlyPerspexList<TIn> inner,
Func<TIn, TOut> convert)
public PerspexReadOnlyListView(Func<TIn, TOut> convert)
: this(null, convert)
{
this.inner = inner;
}
public PerspexReadOnlyListView(IReadOnlyPerspexList<TIn> source, Func<TIn, TOut> convert)
{
this.source = source;
this.convert = convert;
this.inner.CollectionChanged += this.InnerCollectionChanged;
if (source != null)
{
this.source.CollectionChanged += this.SourceCollectionChanged;
}
}
public TOut this[int index]
{
get { return this.convert(this.inner[index]); }
get
{
return (this.convert != null) ?
this.convert(this.source[index]) :
(TOut)(object)this.source[index];
}
}
public int Count
{
get { return this.inner.Count; }
get { return this.source.Count; }
}
public IReadOnlyPerspexList<TIn> Source
{
get
{
return this.source;
}
set
{
if (this.source != null)
{
this.source.CollectionChanged -= this.SourceCollectionChanged;
if (this.CollectionChanged != null)
{
var ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove,
this.ConvertList(this.source),
0);
this.CollectionChanged(this, ev);
}
}
this.source = value;
if (this.source != null)
{
this.source.CollectionChanged += this.SourceCollectionChanged;
if (this.CollectionChanged != null)
{
var ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
this.ConvertList(this.source),
0);
this.CollectionChanged(this, ev);
}
}
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
@ -44,12 +223,22 @@ namespace Perspex.Collections
public void Dispose()
{
this.inner.CollectionChanged -= this.InnerCollectionChanged;
if (this.source != null)
{
this.source.CollectionChanged -= this.SourceCollectionChanged;
}
}
public IEnumerator<TOut> GetEnumerator()
{
return this.inner.Select(convert).GetEnumerator();
if (this.source != null)
{
return this.source.Select(this.convert).GetEnumerator();
}
else
{
return Enumerable.Empty<TOut>().GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator()
@ -57,12 +246,12 @@ namespace Perspex.Collections
return this.GetEnumerator();
}
private IList<TOut> ConvertList(IList list)
private IList<TOut> ConvertList(IEnumerable list)
{
return list.Cast<TIn>().Select(this.convert).ToList();
}
private void InnerCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
private void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (this.CollectionChanged != null)
{
@ -82,6 +271,14 @@ namespace Perspex.Collections
this.ConvertList(e.OldItems),
e.NewStartingIndex);
break;
case NotifyCollectionChangedAction.Replace:
ev = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Replace,
this.ConvertList(e.NewItems),
this.ConvertList(e.OldItems),
e.OldStartingIndex);
break;
default:
throw new NotSupportedException("Action not yet implemented.");
}
@ -90,4 +287,5 @@ namespace Perspex.Collections
}
}
}
}

2
Perspex.Base/Collections/SingleItemPerspexList.cs

@ -66,7 +66,7 @@ namespace Perspex.Collections
NotifyCollectionChangedEventArgs e = null;
bool countChanged = false;
if (value == null && this.item != null )
if (value == null && this.item != null)
{
e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, this.item, 0);
this.item = null;

13
Perspex.Controls/ItemsControl.cs

@ -32,7 +32,8 @@ namespace Perspex.Controls
private ItemContainerGenerator itemContainerGenerator;
private PerspexReadOnlyListView<IVisual, ILogical> logicalChildren;
private PerspexReadOnlyListView<IVisual, ILogical> logicalChildren =
new PerspexReadOnlyListView<IVisual, ILogical>(x => (ILogical)x);
private ItemsPresenter presenter;
@ -82,19 +83,11 @@ namespace Perspex.Controls
protected override void OnTemplateApplied()
{
if (this.logicalChildren != null)
{
this.logicalChildren.Dispose();
this.logicalChildren = null;
}
this.presenter = this.FindTemplateChild<ItemsPresenter>("itemsPresenter");
if (this.presenter != null)
{
this.logicalChildren = new PerspexReadOnlyListView<IVisual, ILogical>(
((IVisual)presenter.Panel).VisualChildren,
x => (ILogical)x);
this.logicalChildren.Source = ((IVisual)this.presenter).VisualChildren;
}
}

20
Tests/Perspex.Controls.UnitTests/ItemsControlTests.cs

@ -218,6 +218,26 @@ namespace Perspex.Controls.UnitTests
Assert.True(called);
}
[Fact]
public void LogicalChildren_Should_Not_Change_Instance_When_Template_Changed()
{
var target = new ItemsControl()
{
Template = this.GetTemplate(),
};
var before = ((ILogical)target).LogicalChildren;
target.Template = null;
target.Template = this.GetTemplate();
var after = ((ILogical)target).LogicalChildren;
Assert.NotNull(before);
Assert.NotNull(after);
Assert.Same(before, after);
}
private ControlTemplate GetTemplate()
{
return ControlTemplate.Create<ItemsControl>(parent =>

Loading…
Cancel
Save