Browse Source

Make ContentControl child be logical child.

The control this is created by the ContentPresenter now appears as the
logical child of the parent ContentControl.
pull/39/head
Steven Kirk 11 years ago
parent
commit
309ac30a41
  1. 36
      Perspex.Controls.UnitTests/ContentControlTests.cs
  2. 20
      Perspex.Controls/ContentControl.cs
  3. 47
      Perspex.Controls/Presenters/ContentPresenter.cs
  4. 3
      Perspex.Themes.Default/ContentControlStyle.cs
  5. 1
      Perspex.Themes.Default/WindowStyle.cs

36
Perspex.Controls.UnitTests/ContentControlTests.cs

@ -125,11 +125,28 @@ namespace Perspex.Controls.UnitTests
var target = new ContentControl();
var child = new Control();
target.Template = this.GetTemplate();
target.Content = child;
target.ApplyTemplate();
CollectionAssert.AreEqual(new[] { child }, ((ILogical)target).LogicalChildren.ToList());
}
[TestMethod]
public void Setting_Content_To_String_Should_Make_TextBlock_Appear_In_LogicalChildren()
{
var target = new ContentControl();
var child = new Control();
target.Template = this.GetTemplate();
target.Content = "Foo";
target.ApplyTemplate();
var logical = (ILogical)target;
Assert.AreEqual(1, logical.LogicalChildren.Count);
Assert.IsInstanceOfType(logical.LogicalChildren[0], typeof(TextBlock));
}
[TestMethod]
public void Clearing_Content_Should_Remove_From_LogicalChildren()
{
@ -152,7 +169,13 @@ namespace Perspex.Controls.UnitTests
((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) =>
called = e.Action == NotifyCollectionChangedAction.Add;
contentControl.Template = this.GetTemplate();
contentControl.Content = child;
contentControl.ApplyTemplate();
// Need to call ApplyTemplate on presenter for CollectionChanged to be called.
var presenter = contentControl.GetTemplateControls().Single(x => x.Id == "presenter");
presenter.ApplyTemplate();
Assert.IsTrue(called);
}
@ -164,13 +187,19 @@ namespace Perspex.Controls.UnitTests
var child = new Control();
var called = false;
contentControl.Template = this.GetTemplate();
contentControl.Content = child;
ApplyTemplate(contentControl);
((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) =>
called = e.Action == NotifyCollectionChangedAction.Remove;
contentControl.Content = null;
// Need to call ApplyTemplate on presenter for CollectionChanged to be called.
var presenter = contentControl.GetTemplateControls().Single(x => x.Id == "presenter");
presenter.ApplyTemplate();
Assert.IsTrue(called);
}
@ -182,13 +211,19 @@ namespace Perspex.Controls.UnitTests
var child2 = new Control();
var called = false;
contentControl.Template = this.GetTemplate();
contentControl.Content = child1;
contentControl.ApplyTemplate();
((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) =>
called = e.Action == NotifyCollectionChangedAction.Replace;
contentControl.Content = child2;
// Need to call ApplyTemplate on presenter for CollectionChanged to be called.
var presenter = contentControl.GetTemplateControls().Single(x => x.Id == "presenter");
presenter.ApplyTemplate();
Assert.IsTrue(called);
}
@ -206,6 +241,7 @@ namespace Perspex.Controls.UnitTests
Background = new Perspex.Media.SolidColorBrush(0xffffffff),
Content = new ContentPresenter
{
Id = "presenter",
[~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty],
}
};

20
Perspex.Controls/ContentControl.cs

@ -8,6 +8,7 @@ namespace Perspex.Controls
{
using System;
using Perspex.Collections;
using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives;
using Perspex.Layout;
@ -24,6 +25,10 @@ namespace Perspex.Controls
private SingleItemPerspexList<ILogical> logicalChild = new SingleItemPerspexList<ILogical>();
private ContentPresenter presenter;
private IDisposable presenterSubscription;
public ContentControl()
{
this.GetObservableWithHistory(ContentProperty).Subscribe(x =>
@ -40,8 +45,6 @@ namespace Perspex.Controls
{
control2.Parent = this;
}
this.logicalChild.SingleItem = control2;
});
}
@ -67,5 +70,18 @@ namespace Perspex.Controls
get { return this.GetValue(VerticalContentAlignmentProperty); }
set { this.SetValue(VerticalContentAlignmentProperty, value); }
}
protected override void OnTemplateApplied()
{
if (this.presenterSubscription != null)
{
this.presenterSubscription.Dispose();
this.presenterSubscription = null;
}
this.presenter = this.GetTemplateChild<ContentPresenter>("presenter");
this.presenterSubscription = this.presenter.ChildObservable
.Subscribe(x => this.logicalChild.SingleItem = x);
}
}
}

47
Perspex.Controls/Presenters/ContentPresenter.cs

@ -9,8 +9,8 @@ namespace Perspex.Controls.Presenters
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Perspex.Controls.Primitives;
using Perspex.Layout;
public class ContentPresenter : Control, IVisual
{
@ -19,11 +19,44 @@ namespace Perspex.Controls.Presenters
private bool createdChild;
private Control child;
private BehaviorSubject<Control> childObservable = new BehaviorSubject<Control>(null);
public ContentPresenter()
{
this.GetObservable(ContentProperty).Skip(1).Subscribe(this.ContentChanged);
}
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; }
}
public object Content
{
get { return this.GetValue(ContentProperty); }
@ -45,12 +78,10 @@ namespace Perspex.Controls.Presenters
protected override Size MeasureOverride(Size availableSize)
{
Control child = ((IVisual)this).VisualChildren.SingleOrDefault() as Control;
if (child != null)
if (this.child != null)
{
child.Measure(availableSize);
return child.DesiredSize.Value;
this.child.Measure(availableSize);
return this.child.DesiredSize.Value;
}
return new Size();
@ -64,13 +95,13 @@ namespace Perspex.Controls.Presenters
private void CreateChild()
{
Control result = null;
object content = this.Content;
this.ClearVisualChildren();
if (content != null)
{
Control result;
if (content is Control)
{
@ -101,9 +132,9 @@ namespace Perspex.Controls.Presenters
}
result.TemplatedParent = foo;
this.AddVisualChild(result);
}
this.Child = result;
this.createdChild = true;
}
}

3
Perspex.Themes.Default/ContentControlStyle.cs

@ -31,7 +31,8 @@ namespace Perspex.Themes.Default
private Control Template(ContentControl control)
{
return new ContentPresenter
{
{
Id = "presenter",
[~ContentPresenter.ContentProperty] = control[~ContentControl.ContentProperty],
};
}

1
Perspex.Themes.Default/WindowStyle.cs

@ -37,6 +37,7 @@ namespace Perspex.Themes.Default
[~Border.BackgroundProperty] = control[~Window.BackgroundProperty],
Content = new ContentPresenter
{
Id = "presenter",
[~ContentPresenter.ContentProperty] = control[~Window.ContentProperty],
}
};

Loading…
Cancel
Save