Browse Source

Added IContentPresenterHost.

Similarly to how we now have IItemsPresenterHost.
pull/316/merge
Steven Kirk 10 years ago
parent
commit
4845dfd0fa
  1. 13
      src/Perspex.Controls/ContentControl.cs
  2. 1
      src/Perspex.Controls/Perspex.Controls.csproj
  3. 6
      src/Perspex.Controls/Presenters/ContentPresenter.cs
  4. 27
      src/Perspex.Controls/Presenters/IContentPresenterHost.cs
  5. 26
      tests/Perspex.Controls.UnitTests/ContentControlTests.cs
  6. 4
      tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs
  7. 4
      tests/Perspex.Controls.UnitTests/ListBoxTests.cs
  8. 2
      tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs
  9. 12
      tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs
  10. 2
      tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs

13
src/Perspex.Controls/ContentControl.cs

@ -16,7 +16,7 @@ namespace Perspex.Controls
/// <summary>
/// Displays <see cref="Content"/> according to a <see cref="FuncDataTemplate"/>.
/// </summary>
public class ContentControl : TemplatedControl, IContentControl
public class ContentControl : TemplatedControl, IContentControl, IContentPresenterHost
{
/// <summary>
/// Defines the <see cref="Content"/> property.
@ -57,7 +57,7 @@ namespace Perspex.Controls
/// <summary>
/// Gets the presenter from the control's template.
/// </summary>
public ContentPresenter Presenter
public IContentPresenter Presenter
{
get;
private set;
@ -82,14 +82,9 @@ namespace Perspex.Controls
}
/// <inheritdoc/>
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
void IContentPresenterHost.RegisterContentPresenter(IContentPresenter presenter)
{
base.OnTemplateApplied(e);
// 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.
Presenter = e.NameScope.Find<ContentPresenter>("PART_ContentPresenter");
Presenter = presenter;
}
}
}

1
src/Perspex.Controls/Perspex.Controls.csproj

@ -57,6 +57,7 @@
<Compile Include="Platform\ITopLevelRenderer.cs" />
<Compile Include="Platform\IWindowingPlatform.cs" />
<Compile Include="Platform\PlatformManager.cs" />
<Compile Include="Presenters\IContentPresenterHost.cs" />
<Compile Include="Presenters\IItemsPresenterHost.cs" />
<Compile Include="Primitives\HeaderedSelectingControl.cs" />
<Compile Include="Primitives\IScrollable.cs" />

6
src/Perspex.Controls/Presenters/ContentPresenter.cs

@ -34,6 +34,7 @@ namespace Perspex.Controls.Presenters
static ContentPresenter()
{
ContentProperty.Changed.AddClassHandler<ContentPresenter>(x => x.ContentChanged);
TemplatedParentProperty.Changed.AddClassHandler<ContentPresenter>(x => x.TemplatedParentChanged);
}
/// <summary>
@ -146,5 +147,10 @@ namespace Perspex.Controls.Presenters
_createdChild = false;
InvalidateMeasure();
}
private void TemplatedParentChanged(PerspexPropertyChangedEventArgs e)
{
(e.NewValue as IContentPresenterHost)?.RegisterContentPresenter(this);
}
}
}

27
src/Perspex.Controls/Presenters/IContentPresenterHost.cs

@ -0,0 +1,27 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Perspex.Styling;
namespace Perspex.Controls.Presenters
{
/// <summary>
/// Represents a control which hosts a content presenter.
/// </summary>
/// <remarks>
/// This interface is implemented by <see cref="ContentControl"/> which usually contains a
/// <see cref="ContentPresenter"/> and exposes it through its
/// <see cref="ContentControl.Presenter"/> property. ContentPresenters can be within
/// nested templates or in popups and so are not necessarily created immediately when the
/// parent control's template is instantiated so they register themselves using this
/// interface.
/// </remarks>
public interface IContentPresenterHost : ITemplatedControl
{
/// <summary>
/// Registers an <see cref="IContentPresenter"/> with a host control.
/// </summary>
/// <param name="presenter">The content presenter.</param>
void RegisterContentPresenter(IContentPresenter presenter);
}
}

26
tests/Perspex.Controls.UnitTests/ContentControlTests.cs

@ -28,7 +28,7 @@ namespace Perspex.Controls.UnitTests
target.Content = "Foo";
target.Template = GetTemplate();
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
var child = ((IVisual)target).VisualChildren.Single();
Assert.IsType<Border>(child);
@ -71,7 +71,7 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.Content = child;
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
var contentPresenter = child.GetVisualParent<ContentPresenter>();
Assert.Equal(target, contentPresenter.TemplatedParent);
@ -86,7 +86,7 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.Content = child;
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.Null(child.TemplatedParent);
}
@ -117,7 +117,7 @@ namespace Perspex.Controls.UnitTests
target.Content = "Foo";
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
var child = target.Presenter.Child;
@ -157,7 +157,7 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.Content = child;
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.True(called);
}
@ -172,12 +172,12 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.Content = child;
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = true;
target.Content = null;
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.True(called);
}
@ -193,7 +193,7 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.Content = child1;
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = true;
@ -210,13 +210,13 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
target.Content = "Foo";
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.Equal("Foo", ((TextBlock)target.Presenter.Child).Text);
target.Content = "Bar";
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.Equal("Bar", ((TextBlock)target.Presenter.Child).Text);
}
@ -228,7 +228,7 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.Content = "Foo";
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.Equal("Foo", target.Presenter.Child.DataContext);
}
@ -241,7 +241,7 @@ namespace Perspex.Controls.UnitTests
target.Template = GetTemplate();
target.Content = new TextBlock();
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.Null(target.Presenter.Child.DataContext);
}

4
tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs

@ -28,7 +28,7 @@ namespace Perspex.Controls.UnitTests
};
root.ApplyTemplate();
root.Presenter.UpdateChild();
((ContentPresenter)root.Presenter).UpdateChild();
Assert.Same(root.Find("foo"), root.Content);
Assert.Same(root.Find("bar"), ((Border)root.Content).Child);
@ -70,7 +70,7 @@ namespace Perspex.Controls.UnitTests
root.ApplyTemplate();
Assert.Null(NameScope.GetNameScope(root.Presenter).Find("foo"));
Assert.Null(NameScope.GetNameScope((Control)root.Presenter).Find("foo"));
}
private class TestRoot : ContentControl, IRenderRoot, INameScope, IStyleRoot

4
tests/Perspex.Controls.UnitTests/ListBoxTests.cs

@ -42,7 +42,7 @@ namespace Perspex.Controls.UnitTests
var text = target.Presenter.Panel.Children
.OfType<ListBoxItem>()
.Do(x => x.Template = ListBoxItemTemplate())
.Do(x => { x.ApplyTemplate(); x.Presenter.UpdateChild(); })
.Do(x => { x.ApplyTemplate(); ((ContentPresenter)x.Presenter).UpdateChild(); })
.Select(x => x.Presenter.Child)
.OfType<TextBlock>()
.Select(x => x.Text)
@ -169,7 +169,7 @@ namespace Perspex.Controls.UnitTests
scrollViewer.ApplyTemplate();
// Then make the ScrollViewer create its child.
scrollViewer.Presenter.UpdateChild();
((ContentPresenter)scrollViewer.Presenter).UpdateChild();
// Now the ItemsPresenter should be reigstered, so apply its template.
target.Presenter.ApplyTemplate();

2
tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs

@ -231,7 +231,7 @@ namespace Perspex.Controls.UnitTests
scrollViewer.ApplyTemplate();
// Then make the ScrollViewer create its child.
scrollViewer.Presenter.UpdateChild();
((ContentPresenter)scrollViewer.Presenter).UpdateChild();
// Now the ItemsPresenter should be reigstered, so apply its template.
target.Presenter.ApplyTemplate();

12
tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Linq;
using Moq;
using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
@ -12,6 +13,17 @@ namespace Perspex.Controls.UnitTests.Presenters
{
public class ContentPresenterTests
{
[Fact]
public void Should_Register_With_Host_When_TemplatedParent_Set()
{
var host = new Mock<IContentPresenterHost>();
var target = new ContentPresenter();
target.SetValue(Control.TemplatedParentProperty, host.Object);
host.Verify(x => x.RegisterContentPresenter(target));
}
[Fact]
public void Setting_Content_To_Control_Should_Set_Child()
{

2
tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs

@ -20,7 +20,7 @@ namespace Perspex.Controls.UnitTests
};
target.ApplyTemplate();
target.Presenter.UpdateChild();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.IsType<TextBlock>(target.Presenter.Child);
}

Loading…
Cancel
Save