Browse Source

Make TabControl logical child test pass.

And simplified logic in selecting ContentControl logical child.
pull/39/head
Steven Kirk 11 years ago
parent
commit
fb08924070
  1. 4
      Perspex.Base/Collections/PerspexReadOnlyListView.cs
  2. 25
      Perspex.Controls/ContentControl.cs
  3. 25
      Perspex.Controls/DropDown.cs
  4. 57
      Perspex.Controls/Presenters/ContentPresenter.cs
  5. 7
      Perspex.Controls/TabControl.cs
  6. 15
      Tests/Perspex.Controls.UnitTests/ContentControlTests.cs
  7. 86
      Tests/Perspex.Controls.UnitTests/ContentPresenterTests.cs
  8. 1
      Tests/Perspex.Controls.UnitTests/DropDownTests.cs
  9. 1
      Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj
  10. 2
      Tests/Perspex.Controls.UnitTests/TabControlTests.cs

4
Perspex.Base/Collections/PerspexReadOnlyListView.cs

@ -94,7 +94,9 @@ namespace Perspex.Collections
public IEnumerator<T> GetEnumerator()
{
return this.source.GetEnumerator();
return (this.source != null) ?
this.source.GetEnumerator() :
Enumerable.Empty<T>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()

25
Perspex.Controls/ContentControl.cs

@ -24,11 +24,7 @@ namespace Perspex.Controls
public static readonly PerspexProperty<VerticalAlignment> VerticalContentAlignmentProperty =
PerspexProperty.Register<ContentControl, VerticalAlignment>("VerticalContentAlignment");
private SingleItemPerspexList<ILogical> logicalChild = new SingleItemPerspexList<ILogical>();
private ContentPresenter presenter;
private IDisposable presenterSubscription;
private PerspexReadOnlyListView<ILogical> logicalChildren = new PerspexReadOnlyListView<ILogical>();
public ContentControl()
{
@ -55,26 +51,23 @@ namespace Perspex.Controls
IReadOnlyPerspexList<ILogical> ILogical.LogicalChildren
{
get { return this.logicalChild; }
get { return this.logicalChildren; }
}
protected override void OnTemplateApplied()
{
if (this.presenterSubscription != null)
{
this.presenterSubscription.Dispose();
this.presenterSubscription = null;
}
// We allow ContentControls without ContentPresenters in the template. This can be
// useful for e.g. a simple ToggleButton that displays an image. There's no need to
// have a ContentPresenter in the visual tree for that.
this.presenter = this.FindTemplateChild<ContentPresenter>("contentPresenter");
var presenter = this.FindTemplateChild<ContentPresenter>("contentPresenter");
if (this.presenter != null)
if (presenter != null)
{
this.logicalChildren.Source = ((ILogical)presenter).LogicalChildren;
}
else
{
this.presenterSubscription = this.presenter.ChildObservable
.Subscribe(x => this.logicalChild.SingleItem = x);
this.logicalChildren.Source = null;
}
}

25
Perspex.Controls/DropDown.cs

@ -27,11 +27,7 @@ namespace Perspex.Controls
public static readonly PerspexProperty<bool> IsDropDownOpenProperty =
PerspexProperty.Register<DropDown, bool>("IsDropDownOpen");
private SingleItemPerspexList<ILogical> logicalChild = new SingleItemPerspexList<ILogical>();
private ContentPresenter presenter;
private IDisposable presenterSubscription;
private PerspexReadOnlyListView<ILogical> logicalChildren = new PerspexReadOnlyListView<ILogical>();
public DropDown()
{
@ -65,26 +61,23 @@ namespace Perspex.Controls
IReadOnlyPerspexList<ILogical> ILogical.LogicalChildren
{
get { return this.logicalChild; }
get { return this.logicalChildren; }
}
protected override void OnTemplateApplied()
{
if (this.presenterSubscription != null)
var presenter = this.FindTemplateChild<ContentPresenter>("contentPresenter");
if (presenter != null)
{
this.presenterSubscription.Dispose();
this.presenterSubscription = null;
this.logicalChildren.Source = ((ILogical)presenter).LogicalChildren;
}
this.presenter = this.FindTemplateChild<ContentPresenter>("contentPresenter");
if (this.presenter != null)
else
{
this.presenterSubscription = this.presenter.ChildObservable
.Subscribe(x => this.logicalChild.SingleItem = x);
this.logicalChildren.Source = null;
}
}
private void SetContentParent(Tuple<object, object> change)
{
var control1 = change.Item1 as Control;

57
Perspex.Controls/Presenters/ContentPresenter.cs

@ -10,19 +10,18 @@ namespace Perspex.Controls.Presenters
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Perspex.Collections;
using Perspex.Controls.Primitives;
using Perspex.Media;
public class ContentPresenter : Control, IVisual, IPresenter
public class ContentPresenter : Control, IVisual, ILogical, IPresenter
{
public static readonly PerspexProperty<object> ContentProperty =
ContentControl.ContentProperty.AddOwner<ContentPresenter>();
private bool createdChild;
private Control child;
private BehaviorSubject<Control> childObservable = new BehaviorSubject<Control>(null);
private SingleItemPerspexList<ILogical> logicalChild = new SingleItemPerspexList<ILogical>();
public ContentPresenter()
{
@ -31,31 +30,7 @@ namespace Perspex.Controls.Presenters
public Control Child
{
get
{
return this.child;
}
private set
{
if (this.child != value)
{
this.ClearVisualChildren();
this.child = value;
if (value != null)
{
this.AddVisualChild(value);
}
this.childObservable.OnNext(value);
}
}
}
public IObservable<Control> ChildObservable
{
get { return this.childObservable; }
get { return (Control)this.logicalChild.SingleItem; }
}
public object Content
@ -64,6 +39,11 @@ namespace Perspex.Controls.Presenters
set { this.SetValue(ContentProperty, value); }
}
IReadOnlyPerspexList<ILogical> ILogical.LogicalChildren
{
get { return this.logicalChild; }
}
public override sealed void ApplyTemplate()
{
if (!this.createdChild)
@ -79,10 +59,12 @@ namespace Perspex.Controls.Presenters
protected override Size MeasureOverride(Size availableSize)
{
if (this.child != null)
var child = this.Child;
if (child != null)
{
this.child.Measure(availableSize);
return this.child.DesiredSize.Value;
child.Measure(availableSize);
return child.DesiredSize.Value;
}
return new Size();
@ -124,17 +106,18 @@ namespace Perspex.Controls.Presenters
}
}
var foo = this.TemplatedParent as TemplatedControl;
var templatedParent = this.TemplatedParent as TemplatedControl;
if (foo != null)
if (templatedParent != null)
{
foo = foo.TemplatedParent as TemplatedControl;
templatedParent = templatedParent.TemplatedParent as TemplatedControl;
}
result.TemplatedParent = foo;
result.TemplatedParent = templatedParent;
this.AddVisualChild(result);
}
this.Child = result;
this.logicalChild.SingleItem = result;
this.createdChild = true;
}
}

7
Perspex.Controls/TabControl.cs

@ -15,7 +15,7 @@ namespace Perspex.Controls
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
public class TabControl : SelectingItemsControl
public class TabControl : SelectingItemsControl, ILogical
{
public static readonly PerspexProperty<object> SelectedContentProperty =
PerspexProperty.Register<TabControl, object>("SelectedContent");
@ -50,6 +50,11 @@ namespace Perspex.Controls
set { this.SetValue(SelectedTabProperty, value); }
}
IReadOnlyPerspexList<ILogical> ILogical.LogicalChildren
{
get { return this.logicalChildren; }
}
protected override void OnTemplateApplied()
{
var presenter = this.GetTemplateChild<ContentPresenter>("contentPresenter");

15
Tests/Perspex.Controls.UnitTests/ContentControlTests.cs

@ -150,13 +150,20 @@ namespace Perspex.Controls.UnitTests
[Fact]
public void Clearing_Content_Should_Remove_From_LogicalChildren()
{
var contentControl = new ContentControl();
var target = new ContentControl();
var child = new Control();
contentControl.Content = child;
contentControl.Content = null;
target.Template = this.GetTemplate();
target.Content = child;
target.ApplyTemplate();
target.Content = null;
// Need to call ApplyTemplate on presenter for LogocalChildren to be updated.
var presenter = target.GetTemplateChildren().Single(x => x.Id == "contentPresenter");
presenter.ApplyTemplate();
Assert.Equal(new ILogical[0], ((ILogical)contentControl).LogicalChildren.ToList());
Assert.Equal(new ILogical[0], ((ILogical)target).LogicalChildren.ToList());
}
[Fact]

86
Tests/Perspex.Controls.UnitTests/ContentPresenterTests.cs

@ -0,0 +1,86 @@
// -----------------------------------------------------------------------
// <copyright file="ContentPresenterTests.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.UnitTests
{
using System;
using System.Collections.Specialized;
using System.Linq;
using Moq;
using Perspex.Controls;
using Perspex.Controls.Presenters;
using Perspex.Controls.Templates;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Styling;
using Perspex.VisualTree;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
using Splat;
using Xunit;
public class ContentPresenterTests
{
[Fact]
public void Setting_Content_Should_Make_Control_Appear_In_LogicalChildren()
{
var target = new ContentPresenter();
var child = new Control();
target.Content = child;
target.ApplyTemplate();
Assert.Equal(new[] { child }, ((ILogical)target).LogicalChildren.ToList());
}
[Fact]
public void Clearing_Content_Should_Remove_From_LogicalChildren()
{
var target = new ContentPresenter();
var child = new Control();
target.Content = child;
target.Content = null;
Assert.Equal(new ILogical[0], ((ILogical)target).LogicalChildren.ToList());
}
[Fact]
public void Changing_Content_Should_Fire_LogicalChildren_CollectionChanged()
{
var target = new ContentPresenter();
var child = new Control();
var called = false;
((ILogical)target).LogicalChildren.CollectionChanged += (s, e) =>
called = e.Action == NotifyCollectionChangedAction.Add;
target.Content = child;
target.ApplyTemplate();
Assert.True(called);
}
[Fact]
public void Clearing_Content_Should_Fire_LogicalChildren_CollectionChanged()
{
var target = new ContentPresenter();
var child = new Control();
var called = false;
target.Content = child;
target.ApplyTemplate();
((ILogical)target).LogicalChildren.CollectionChanged += (s, e) =>
called = e.Action == NotifyCollectionChangedAction.Remove;
target.Content = null;
target.ApplyTemplate();
Assert.True(called);
}
}
}

1
Tests/Perspex.Controls.UnitTests/DropDownTests.cs

@ -154,6 +154,7 @@ namespace Perspex.Controls.UnitTests
target.Content = child;
target.Content = null;
target.ApplyTemplate();
Assert.Equal(new ILogical[0], ((ILogical)target).LogicalChildren.ToList());
}

1
Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj

@ -79,6 +79,7 @@
<Otherwise />
</Choose>
<ItemGroup>
<Compile Include="ContentPresenterTests.cs" />
<Compile Include="DropDownTests.cs" />
<Compile Include="ScrollContentPresenterTests.cs" />
<Compile Include="ScrollViewerTests.cs" />

2
Tests/Perspex.Controls.UnitTests/TabControlTests.cs

@ -136,7 +136,7 @@ namespace Perspex.Controls.UnitTests
target.ApplyTemplate();
Assert.Equal(1, target.GetLogicalChildren().Count());
Assert.Equal("Foo", ((TabItem)target.GetLogicalChildren().First()).Id);
Assert.Equal("Foo", ((TextBlock)target.GetLogicalChildren().First()).Id);
}
private Control CreateTabControlTemplate(TabControl parent)

Loading…
Cancel
Save