diff --git a/src/Perspex.Controls/ItemsControl.cs b/src/Perspex.Controls/ItemsControl.cs index 16873b7f05..1c6a51529f 100644 --- a/src/Perspex.Controls/ItemsControl.cs +++ b/src/Perspex.Controls/ItemsControl.cs @@ -21,7 +21,7 @@ namespace Perspex.Controls /// /// Displays a collection of items. /// - public class ItemsControl : TemplatedControl + public class ItemsControl : TemplatedControl, IItemsPresenterHost { /// /// The default value for the property. @@ -127,6 +127,12 @@ namespace Perspex.Controls protected set; } + /// + void IItemsPresenterHost.RegisterItemsPresenter(IItemsPresenter presenter) + { + Presenter = presenter; + } + /// /// Gets the item at the specified index in a collection. /// @@ -243,13 +249,6 @@ namespace Perspex.Controls LogicalChildren.RemoveAll(toRemove); } - /// - protected override void OnTemplateApplied(TemplateAppliedEventArgs e) - { - base.OnTemplateApplied(e); - Presenter = e.NameScope.Find("PART_ItemsPresenter"); - } - /// protected override void OnTemplateChanged(PerspexPropertyChangedEventArgs e) { diff --git a/src/Perspex.Controls/Mixins/ContentControlMixin.cs b/src/Perspex.Controls/Mixins/ContentControlMixin.cs index 65153ed0af..e19cc17ae2 100644 --- a/src/Perspex.Controls/Mixins/ContentControlMixin.cs +++ b/src/Perspex.Controls/Mixins/ContentControlMixin.cs @@ -8,6 +8,7 @@ using Perspex.Collections; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; using Perspex.Interactivity; +using Perspex.Styling; namespace Perspex.Controls.Mixins { @@ -62,6 +63,7 @@ namespace Perspex.Controls.Mixins var subscription = presenter .GetObservable(ContentPresenter.ChildProperty) .Subscribe(child => UpdateLogicalChild( + sender, logicalChildren, logicalChildren.FirstOrDefault(), child)); @@ -82,7 +84,18 @@ namespace Perspex.Controls.Mixins if (sender != null) { var logicalChildren = logicalChildrenSelector(sender); - UpdateLogicalChild(logicalChildren, e.OldValue, e.NewValue); + UpdateLogicalChild(sender, logicalChildren, e.OldValue, e.NewValue); + } + }); + + Control.TemplatedParentProperty.Changed.Subscribe(e => + { + var sender = e.Sender as TControl; + + if (sender != null) + { + var logicalChild = logicalChildrenSelector(sender).FirstOrDefault() as IControl; + logicalChild?.SetValue(Control.TemplatedParentProperty, sender.TemplatedParent); } }); @@ -111,24 +124,26 @@ namespace Perspex.Controls.Mixins } private static void UpdateLogicalChild( + IControl control, IPerspexList logicalChildren, object oldValue, object newValue) { if (oldValue != newValue) { - var logical = oldValue as ILogical; + var child = oldValue as IControl; - if (logical != null) + if (child != null) { - logicalChildren.Remove(logical); + logicalChildren.Remove(child); } - logical = newValue as ILogical; + child = newValue as IControl; - if (logical != null) + if (child != null) { - logicalChildren.Add(logical); + child.SetValue(Control.TemplatedParentProperty, control.TemplatedParent); + logicalChildren.Add(child); } } } diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj index c0fbb8fab3..a0ea1e4084 100644 --- a/src/Perspex.Controls/Perspex.Controls.csproj +++ b/src/Perspex.Controls/Perspex.Controls.csproj @@ -57,6 +57,7 @@ + diff --git a/src/Perspex.Controls/Presenters/CarouselPresenter.cs b/src/Perspex.Controls/Presenters/CarouselPresenter.cs index cee9a053db..bd9d7b8840 100644 --- a/src/Perspex.Controls/Presenters/CarouselPresenter.cs +++ b/src/Perspex.Controls/Presenters/CarouselPresenter.cs @@ -64,6 +64,7 @@ namespace Perspex.Controls.Presenters static CarouselPresenter() { SelectedIndexProperty.Changed.AddClassHandler(x => x.SelectedIndexChanged); + TemplatedParentProperty.Changed.AddClassHandler(x => x.TemplatedParentChanged); } /// @@ -256,5 +257,10 @@ namespace Perspex.Controls.Presenters } } } + + private void TemplatedParentChanged(PerspexPropertyChangedEventArgs e) + { + (e.NewValue as IItemsPresenterHost)?.RegisterItemsPresenter(this); + } } } diff --git a/src/Perspex.Controls/Presenters/ContentPresenter.cs b/src/Perspex.Controls/Presenters/ContentPresenter.cs index 0faa7fd783..fbc2300d02 100644 --- a/src/Perspex.Controls/Presenters/ContentPresenter.cs +++ b/src/Perspex.Controls/Presenters/ContentPresenter.cs @@ -57,12 +57,58 @@ namespace Perspex.Controls.Presenters /// public override sealed void ApplyTemplate() { - if (!_createdChild) + if (!_createdChild && ((ILogical)this).IsAttachedToLogicalTree) { - CreateChild(); + UpdateChild(); } } + /// + /// Updates the control based on the control's . + /// + /// + /// Usually the control is created automatically when + /// is called; however for this to happen, the control needs to + /// be attached to a logical tree (if the control is not attached to the logical tree, it + /// is reasonable to expect that the DataTemplates needed for the child are not yet + /// available). This method forces the control's creation at any point, + /// and is particularly useful in unit tests. + /// + public void UpdateChild() + { + var old = Child; + var content = Content; + var result = this.MaterializeDataTemplate(content); + + if (old != null) + { + VisualChildren.Remove(old); + } + + if (result != null) + { + if (!(content is IControl)) + { + result.DataContext = content; + } + + Child = result; + + if (result.Parent == null) + { + ((ISetLogicalParent)result).SetParent((ILogical)this.TemplatedParent ?? this); + } + + VisualChildren.Add(result); + } + else + { + Child = null; + } + + _createdChild = true; + } + /// protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { @@ -100,37 +146,5 @@ namespace Perspex.Controls.Presenters _createdChild = false; InvalidateMeasure(); } - - /// - /// Creates the control from the . - /// - private void CreateChild() - { - var old = Child; - var content = Content; - var result = this.MaterializeDataTemplate(content); - - if (old != null) - { - VisualChildren.Remove(old); - } - - if (result != null) - { - if (!(content is IControl)) - { - result.DataContext = content; - } - - Child = result; - VisualChildren.Add(result); - } - else - { - Child = null; - } - - _createdChild = true; - } } } diff --git a/src/Perspex.Controls/Presenters/IItemsPresenterHost.cs b/src/Perspex.Controls/Presenters/IItemsPresenterHost.cs new file mode 100644 index 0000000000..47f50eb862 --- /dev/null +++ b/src/Perspex.Controls/Presenters/IItemsPresenterHost.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 +{ + /// + /// Represents a control which hosts an items presenter. + /// + /// + /// This interface is implemented by which usually contains an + /// and exposes it through its + /// property. ItemsPresenters 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. + /// + public interface IItemsPresenterHost : ITemplatedControl + { + /// + /// Registers an with a host control. + /// + /// The items presenter. + void RegisterItemsPresenter(IItemsPresenter presenter); + } +} diff --git a/src/Perspex.Controls/Presenters/ItemsPresenter.cs b/src/Perspex.Controls/Presenters/ItemsPresenter.cs index 6f052af7f7..c2eb692b7a 100644 --- a/src/Perspex.Controls/Presenters/ItemsPresenter.cs +++ b/src/Perspex.Controls/Presenters/ItemsPresenter.cs @@ -49,6 +49,7 @@ namespace Perspex.Controls.Presenters typeof(ItemsPresenter), KeyboardNavigationMode.Once); ItemsProperty.Changed.AddClassHandler(x => x.ItemsChanged); + TemplatedParentProperty.Changed.AddClassHandler(x => x.TemplatedParentChanged); } /// @@ -270,6 +271,11 @@ namespace Perspex.Controls.Presenters } } + private void TemplatedParentChanged(PerspexPropertyChangedEventArgs e) + { + (e.NewValue as IItemsPresenterHost)?.RegisterItemsPresenter(this); + } + private void AddContainers(IEnumerable items) { foreach (var i in items) diff --git a/src/Perspex.Controls/Primitives/PopupRoot.cs b/src/Perspex.Controls/Primitives/PopupRoot.cs index 0847780bd8..5347ef9180 100644 --- a/src/Perspex.Controls/Primitives/PopupRoot.cs +++ b/src/Perspex.Controls/Primitives/PopupRoot.cs @@ -96,6 +96,7 @@ namespace Perspex.Controls.Primitives _presenterSubscription = null; } + Presenter?.ApplyTemplate(); Presenter?.GetObservable(ContentPresenter.ChildProperty) .Subscribe(SetTemplatedParentAndApplyChildTemplates); } diff --git a/src/Perspex.Controls/Primitives/TemplatedControl.cs b/src/Perspex.Controls/Primitives/TemplatedControl.cs index 09b90a2e1e..e0bd785e97 100644 --- a/src/Perspex.Controls/Primitives/TemplatedControl.cs +++ b/src/Perspex.Controls/Primitives/TemplatedControl.cs @@ -212,20 +212,9 @@ namespace Perspex.Controls.Primitives var child = Template.Build(this); var nameScope = new NameScope(); NameScope.SetNameScope((Control)child, nameScope); - - // We need to call SetupTemplateControls twice: - // - Once before the controls are added to the visual/logical trees so that the - // TemplatedParent property is set and names are registered; if - // TemplatedParent is not set when the control is added to the logical tree, - // then styles with the /template/ selector won't match. - // - Once after the controls are added to the logical tree (and thus styled) to - // call ApplyTemplate on nested templated controls and register any of our - // templated children that appear as children of presenters in these nested - // templated child controls. SetupTemplateControls(child, nameScope); - VisualChildren.Add(child); ((ISetLogicalParent)child).SetParent(this); - SetupTemplateControls(child, nameScope); + VisualChildren.Add(child); OnTemplateApplied(new TemplateAppliedEventArgs(nameScope)); } @@ -290,8 +279,6 @@ namespace Perspex.Controls.Primitives } } - control.ApplyTemplate(); - if (!(control is IPresenter && control.TemplatedParent == this)) { foreach (IControl child in control.GetVisualChildren()) diff --git a/src/Perspex.Controls/ScrollViewer.cs b/src/Perspex.Controls/ScrollViewer.cs index f8a712cd6a..6391918325 100644 --- a/src/Perspex.Controls/ScrollViewer.cs +++ b/src/Perspex.Controls/ScrollViewer.cs @@ -120,8 +120,6 @@ namespace Perspex.Controls nameof(VerticalScrollBarVisibility), ScrollBarVisibility.Auto); - private IDisposable _scrollableSubscription; - /// /// Initializes static members of the class. /// diff --git a/tests/Perspex.Controls.UnitTests/CarouselTests.cs b/tests/Perspex.Controls.UnitTests/CarouselTests.cs index b1a0a871cd..1fd78655e1 100644 --- a/tests/Perspex.Controls.UnitTests/CarouselTests.cs +++ b/tests/Perspex.Controls.UnitTests/CarouselTests.cs @@ -45,6 +45,7 @@ namespace Perspex.Controls.UnitTests }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); Assert.Equal(1, target.GetLogicalChildren().Count()); @@ -57,7 +58,7 @@ namespace Perspex.Controls.UnitTests { return new CarouselPresenter { - Name = "itemsPresenter", + Name = "PART_ItemsPresenter", [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty], [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], [~CarouselPresenter.SelectedIndexProperty] = control[~SelectingItemsControl.SelectedIndexProperty], diff --git a/tests/Perspex.Controls.UnitTests/ContentControlTests.cs b/tests/Perspex.Controls.UnitTests/ContentControlTests.cs index ff0c993af6..a74eabe9e7 100644 --- a/tests/Perspex.Controls.UnitTests/ContentControlTests.cs +++ b/tests/Perspex.Controls.UnitTests/ContentControlTests.cs @@ -27,8 +27,8 @@ namespace Perspex.Controls.UnitTests var target = new ContentControl(); target.Content = "Foo"; target.Template = GetTemplate(); - - target.Measure(new Size(100, 100)); + target.ApplyTemplate(); + target.Presenter.UpdateChild(); var child = ((IVisual)target).VisualChildren.Single(); Assert.IsType(child); @@ -54,6 +54,7 @@ namespace Perspex.Controls.UnitTests root.Child = target; target.ApplyTemplate(); + target.Presenter.UpdateChild(); styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Once()); @@ -71,6 +72,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); + target.Presenter.UpdateChild(); var contentPresenter = child.GetVisualParent(); Assert.Equal(target, contentPresenter.TemplatedParent); @@ -85,6 +87,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.Null(child.TemplatedParent); } @@ -115,6 +118,7 @@ namespace Perspex.Controls.UnitTests target.Content = "Foo"; target.ApplyTemplate(); + target.Presenter.UpdateChild(); var child = target.Presenter.Child; @@ -131,6 +135,9 @@ namespace Perspex.Controls.UnitTests var child = new Control(); target.Content = child; + + Assert.Equal(new[] { child }, target.GetLogicalChildren()); + target.Content = null; Assert.Null(child.Parent); @@ -151,7 +158,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.True(called); } @@ -166,11 +173,12 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Content = child; target.ApplyTemplate(); + target.Presenter.UpdateChild(); ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = true; target.Content = null; - target.Presenter.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.True(called); } @@ -178,19 +186,20 @@ namespace Perspex.Controls.UnitTests [Fact] public void Changing_Content_Should_Fire_LogicalChildren_CollectionChanged() { - var contentControl = new ContentControl(); + var target = new ContentControl(); var child1 = new Control(); var child2 = new Control(); var called = false; - contentControl.Template = GetTemplate(); - contentControl.Content = child1; - contentControl.ApplyTemplate(); + target.Template = GetTemplate(); + target.Content = child1; + target.ApplyTemplate(); + target.Presenter.UpdateChild(); - ((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) => called = true; + ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = true; - contentControl.Content = child2; - contentControl.Presenter.ApplyTemplate(); + target.Content = child2; + target.Presenter.ApplyTemplate(); Assert.True(called); } @@ -202,12 +211,13 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.ApplyTemplate(); + target.Presenter.UpdateChild(); target.Content = "Foo"; - target.Presenter.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.Equal("Foo", ((TextBlock)target.Presenter.Child).Text); target.Content = "Bar"; - target.Presenter.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.Equal("Bar", ((TextBlock)target.Presenter.Child).Text); } @@ -219,6 +229,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Content = "Foo"; target.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.Equal("Foo", target.Presenter.Child.DataContext); } @@ -231,6 +242,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Content = new TextBlock(); target.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.Null(target.Presenter.Child.DataContext); } diff --git a/tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs b/tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs index ec5f657877..57d0a0a7e7 100644 --- a/tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs +++ b/tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs @@ -28,6 +28,7 @@ namespace Perspex.Controls.UnitTests }; root.ApplyTemplate(); + root.Presenter.UpdateChild(); Assert.Same(root.Find("foo"), root.Content); Assert.Same(root.Find("bar"), ((Border)root.Content).Child); diff --git a/tests/Perspex.Controls.UnitTests/HeaderedItemsControlTests .cs b/tests/Perspex.Controls.UnitTests/HeaderedItemsControlTests .cs index 3eb4db00de..b0d61a1380 100644 --- a/tests/Perspex.Controls.UnitTests/HeaderedItemsControlTests .cs +++ b/tests/Perspex.Controls.UnitTests/HeaderedItemsControlTests .cs @@ -37,6 +37,7 @@ namespace Perspex.Controls.UnitTests target.Header = "Foo"; target.ApplyTemplate(); + target.HeaderPresenter.UpdateChild(); var child = target.HeaderPresenter.Child; diff --git a/tests/Perspex.Controls.UnitTests/ItemsControlTests.cs b/tests/Perspex.Controls.UnitTests/ItemsControlTests.cs index 9cc960a5c2..49aba552fc 100644 --- a/tests/Perspex.Controls.UnitTests/ItemsControlTests.cs +++ b/tests/Perspex.Controls.UnitTests/ItemsControlTests.cs @@ -22,6 +22,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Items = new[] { "Foo" }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); Assert.Equal(target, target.Presenter.Panel.TemplatedParent); } @@ -34,6 +35,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Items = new[] { "Foo" }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); var item = (TextBlock)target.Presenter.Panel.GetVisualChildren().First(); @@ -125,6 +127,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Items = new[] { "Foo" }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); var logical = (ILogical)target; Assert.Equal(1, logical.LogicalChildren.Count); @@ -140,6 +143,10 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Items = new[] { "Foo" }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + + Assert.NotEmpty(target.GetLogicalChildren()); + target.Items = null; Assert.Equal(new ILogical[0], target.GetLogicalChildren()); @@ -210,6 +217,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Items = items; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = e.Action == NotifyCollectionChangedAction.Add; @@ -229,6 +237,7 @@ namespace Perspex.Controls.UnitTests target.Template = GetTemplate(); target.Items = items; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); ((ILogical)target).LogicalChildren.CollectionChanged += (s, e) => called = e.Action == NotifyCollectionChangedAction.Remove; @@ -339,6 +348,7 @@ namespace Perspex.Controls.UnitTests }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); var dataContexts = target.Presenter.Panel.Children .Cast() @@ -361,6 +371,7 @@ namespace Perspex.Controls.UnitTests }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); var text = target.Presenter.Panel.Children .Cast() diff --git a/tests/Perspex.Controls.UnitTests/ListBoxTests.cs b/tests/Perspex.Controls.UnitTests/ListBoxTests.cs index 08c445e8df..eedd1a8682 100644 --- a/tests/Perspex.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Perspex.Controls.UnitTests/ListBoxTests.cs @@ -7,12 +7,26 @@ using Perspex.Controls.Templates; using Perspex.Input; using Perspex.LogicalTree; using Perspex.Styling; +using Perspex.VisualTree; using Xunit; namespace Perspex.Controls.UnitTests { public class ListBoxTests { + [Fact] + public void ListBox_Should_Find_ItemsPresenter_In_ScrollViewer() + { + var target = new ListBox + { + Template = new FuncControlTemplate(CreateListBoxTemplate), + }; + + ApplyTemplate(target); + + Assert.IsType(target.Presenter); + } + [Fact] public void ListBoxItem_Containers_Should_Be_Generated() { @@ -23,12 +37,12 @@ namespace Perspex.Controls.UnitTests Items = items, }; - target.ApplyTemplate(); + ApplyTemplate(target); var text = target.Presenter.Panel.Children .OfType() .Do(x => x.Template = ListBoxItemTemplate()) - .Do(x => x.ApplyTemplate()) + .Do(x => { x.ApplyTemplate(); x.Presenter.UpdateChild(); }) .Select(x => x.Presenter.Child) .OfType() .Select(x => x.Text) @@ -46,7 +60,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplate(target); Assert.Equal(3, target.GetLogicalChildren().Count()); @@ -78,7 +92,7 @@ namespace Perspex.Controls.UnitTests Items = items, }; - target.ApplyTemplate(); + ApplyTemplate(target); var dataContexts = target.Presenter.Panel.Children .Cast() @@ -99,7 +113,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.Presenter.Panel.Children[1].RaiseEvent(new PointerPressEventArgs { @@ -140,10 +154,27 @@ namespace Perspex.Controls.UnitTests { return new ScrollContentPresenter { + Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = parent.GetObservable(ContentControl.ContentProperty), }; } + private void ApplyTemplate(ListBox target) + { + // Apply the template to the ListBox itself. + target.ApplyTemplate(); + + // Then to its inner ScrollViewer. + var scrollViewer = (ScrollViewer)target.GetVisualChildren().Single(); + scrollViewer.ApplyTemplate(); + + // Then make the ScrollViewer create its child. + scrollViewer.Presenter.UpdateChild(); + + // Now the ItemsPresenter should be reigstered, so apply its template. + target.Presenter.ApplyTemplate(); + } + private class Item { public Item(string value) diff --git a/tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs b/tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs index a6f02dc27b..4622d77159 100644 --- a/tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs +++ b/tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs @@ -7,6 +7,7 @@ using Perspex.Controls.Templates; using Perspex.Input; using Perspex.LogicalTree; using Perspex.Styling; +using Perspex.VisualTree; using Xunit; namespace Perspex.Controls.UnitTests @@ -22,7 +23,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs { @@ -42,7 +43,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs { @@ -62,7 +63,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs { @@ -82,7 +83,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.SelectedIndex = 0; target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs @@ -104,7 +105,7 @@ namespace Perspex.Controls.UnitTests SelectionMode = SelectionMode.Single | SelectionMode.Toggle, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs { @@ -125,7 +126,7 @@ namespace Perspex.Controls.UnitTests SelectionMode = SelectionMode.Toggle, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.SelectedIndex = 0; target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs @@ -147,7 +148,7 @@ namespace Perspex.Controls.UnitTests SelectionMode = SelectionMode.Toggle | SelectionMode.AlwaysSelected, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.SelectedIndex = 0; target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs @@ -169,7 +170,7 @@ namespace Perspex.Controls.UnitTests SelectionMode = SelectionMode.Single | SelectionMode.Toggle, }; - target.ApplyTemplate(); + ApplyTemplate(target); target.SelectedIndex = 1; target.Presenter.Panel.Children[0].RaiseEvent(new PointerPressEventArgs @@ -190,7 +191,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplate(target); ((ListBoxItem)target.GetLogicalChildren().ElementAt(1)).IsSelected = true; @@ -215,10 +216,27 @@ namespace Perspex.Controls.UnitTests { return new ScrollContentPresenter { + Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = parent.GetObservable(ContentControl.ContentProperty), }; } + private void ApplyTemplate(ListBox target) + { + // Apply the template to the ListBox itself. + target.ApplyTemplate(); + + // Then to its inner ScrollViewer. + var scrollViewer = (ScrollViewer)target.GetVisualChildren().Single(); + scrollViewer.ApplyTemplate(); + + // Then make the ScrollViewer create its child. + scrollViewer.Presenter.UpdateChild(); + + // Now the ItemsPresenter should be reigstered, so apply its template. + target.Presenter.ApplyTemplate(); + } + private class Item { public Item(string value) diff --git a/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs b/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs index 7997e0cb90..3d715b93fb 100644 --- a/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs +++ b/tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs @@ -1,6 +1,7 @@ // 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 Moq; using Perspex.Controls.Generators; using Perspex.Controls.Presenters; using Perspex.Controls.Templates; @@ -10,6 +11,17 @@ namespace Perspex.Controls.UnitTests.Presenters { public class CarouselPresenterTests { + [Fact] + public void Should_Register_With_Host_When_TemplatedParent_Set() + { + var host = new Mock(); + var target = new CarouselPresenter(); + + target.SetValue(Control.TemplatedParentProperty, host.Object); + + host.Verify(x => x.RegisterItemsPresenter(target)); + } + [Fact] public void ApplyTemplate_Should_Create_Panel() { diff --git a/tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs b/tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs index 3bc0465dc4..91b523a299 100644 --- a/tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs +++ b/tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs @@ -1,8 +1,11 @@ // 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 System.Linq; using Perspex.Controls.Presenters; +using Perspex.Controls.Primitives; using Perspex.Controls.Templates; +using Perspex.VisualTree; using Xunit; namespace Perspex.Controls.UnitTests.Presenters @@ -17,11 +20,8 @@ namespace Perspex.Controls.UnitTests.Presenters target.Content = child; - // Child should not update until ApplyTemplate called. Assert.Null(target.Child); - - target.ApplyTemplate(); - + target.UpdateChild(); Assert.Equal(child, target.Child); } @@ -32,13 +32,39 @@ namespace Perspex.Controls.UnitTests.Presenters target.Content = "Foo"; - // Child should not update until ApplyTemplate called. Assert.Null(target.Child); + target.UpdateChild(); + Assert.IsType(target.Child); + Assert.Equal("Foo", ((TextBlock)target.Child).Text); + } + + [Fact] + public void Should_Set_Childs_Parent_To_TemplatedParent() + { + var content = new Border(); + var target = new TestContentControl + { + Template = new FuncControlTemplate(parent => + new ContentPresenter { Content = parent.Child }), + Child = content, + }; target.ApplyTemplate(); + var presenter = ((ContentPresenter)target.GetVisualChildren().Single()); + presenter.UpdateChild(); - Assert.IsType(target.Child); - Assert.Equal("Foo", ((TextBlock)target.Child).Text); + Assert.Same(target, content.Parent); + } + + [Fact] + public void Should_Set_Childs_Parent_To_Itself_Outside_Template() + { + var content = new Border(); + var target = new ContentPresenter { Content = content }; + + target.UpdateChild(); + + Assert.Same(target, content.Parent); } [Fact] @@ -49,7 +75,7 @@ namespace Perspex.Controls.UnitTests.Presenters Content = "Foo", }; - target.ApplyTemplate(); + target.UpdateChild(); Assert.IsType(target.Child); var root = new TestRoot @@ -64,5 +90,10 @@ namespace Perspex.Controls.UnitTests.Presenters target.ApplyTemplate(); Assert.IsType(target.Child); } + + private class TestContentControl : TemplatedControl + { + public IControl Child { get; set; } + } } } diff --git a/tests/Perspex.Controls.UnitTests/Presenters/ItemsPresenterTests.cs b/tests/Perspex.Controls.UnitTests/Presenters/ItemsPresenterTests.cs index b5fc0a0869..dd7b41caee 100644 --- a/tests/Perspex.Controls.UnitTests/Presenters/ItemsPresenterTests.cs +++ b/tests/Perspex.Controls.UnitTests/Presenters/ItemsPresenterTests.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.Linq; +using Moq; using Perspex.Collections; using Perspex.Controls.Generators; using Perspex.Controls.Presenters; @@ -15,6 +16,17 @@ namespace Perspex.Controls.UnitTests.Presenters { public class ItemsPresenterTests { + [Fact] + public void Should_Register_With_Host_When_TemplatedParent_Set() + { + var host = new Mock(); + var target = new ItemsPresenter(); + + target.SetValue(Control.TemplatedParentProperty, host.Object); + + host.Verify(x => x.RegisterItemsPresenter(target)); + } + [Fact] public void Should_Add_Containers() { diff --git a/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs b/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs index adb4bfd0fa..4f56587bb5 100644 --- a/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs +++ b/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs @@ -25,6 +25,7 @@ namespace Perspex.Controls.UnitTests.Presenters }, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -43,6 +44,7 @@ namespace Perspex.Controls.UnitTests.Presenters }, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -62,6 +64,7 @@ namespace Perspex.Controls.UnitTests.Presenters }, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -81,6 +84,7 @@ namespace Perspex.Controls.UnitTests.Presenters }, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -101,6 +105,7 @@ namespace Perspex.Controls.UnitTests.Presenters }, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -116,6 +121,7 @@ namespace Perspex.Controls.UnitTests.Presenters Content = content = new TestControl(), }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -136,6 +142,7 @@ namespace Perspex.Controls.UnitTests.Presenters Offset = new Vector(25, 25), }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -152,6 +159,7 @@ namespace Perspex.Controls.UnitTests.Presenters [ScrollContentPresenter.CanScrollHorizontallyProperty] = false, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); Assert.Equal(new Size(100, double.PositiveInfinity), child.AvailableSize); @@ -166,6 +174,7 @@ namespace Perspex.Controls.UnitTests.Presenters Content = child, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); Assert.Equal(Size.Infinity, child.AvailableSize); @@ -181,6 +190,7 @@ namespace Perspex.Controls.UnitTests.Presenters var set = new List(); + target.UpdateChild(); target.Measure(new Size(100, 100)); target.GetObservable(ScrollViewer.ViewportProperty).Skip(1).Subscribe(_ => set.Add("Viewport")); @@ -199,6 +209,7 @@ namespace Perspex.Controls.UnitTests.Presenters Content = new Border { Width = 140, Height = 150 } }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); target.Offset = new Vector(10, 100); @@ -232,7 +243,7 @@ namespace Perspex.Controls.UnitTests.Presenters } }; - target.ApplyTemplate(); + target.UpdateChild(); target.Measure(Size.Infinity); target.Arrange(new Rect(0, 0, 100, 100)); target.BringDescendentIntoView(target.Child, new Rect(200, 200, 0, 0)); @@ -259,7 +270,7 @@ namespace Perspex.Controls.UnitTests.Presenters } }; - target.ApplyTemplate(); + target.UpdateChild(); target.Measure(Size.Infinity); target.Arrange(new Rect(0, 0, 100, 100)); target.BringDescendentIntoView(border, new Rect(200, 200, 0, 0)); diff --git a/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs b/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs index 0dc1c31462..22f024f2a3 100644 --- a/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs +++ b/tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs @@ -20,6 +20,7 @@ namespace Perspex.Controls.UnitTests Content = scrollable, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); Assert.Equal(new Size(100, 100), scrollable.AvailableSize); @@ -40,6 +41,7 @@ namespace Perspex.Controls.UnitTests Content = scrollable, }; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.Arrange(new Rect(0, 0, 100, 100)); @@ -56,6 +58,7 @@ namespace Perspex.Controls.UnitTests var changed = false; + target.UpdateChild(); target.Measure(new Size(100, 100)); target.GetObservable(ScrollViewer.ViewportProperty).Skip(1).Subscribe(_ => changed = true); @@ -75,7 +78,7 @@ namespace Perspex.Controls.UnitTests Content = scrollable }; - target.ApplyTemplate(); + target.UpdateChild(); Assert.NotNull(scrollable.InvalidateScroll); } @@ -89,9 +92,9 @@ namespace Perspex.Controls.UnitTests Content = scrollable }; - target.ApplyTemplate(); + target.UpdateChild(); target.Content = null; - target.ApplyTemplate(); + target.UpdateChild(); Assert.Null(scrollable.InvalidateScroll); } @@ -111,7 +114,7 @@ namespace Perspex.Controls.UnitTests Content = scrollable }; - target.ApplyTemplate(); + target.UpdateChild(); Assert.Equal(scrollable.Extent, target.Extent); Assert.Equal(scrollable.Offset, target.Offset); @@ -140,8 +143,7 @@ namespace Perspex.Controls.UnitTests Content = scrollable }; - target.ApplyTemplate(); - + target.UpdateChild(); target.Offset = new Vector(25, 25); Assert.Equal(target.Offset, scrollable.Offset); diff --git a/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index c61c81e8ce..9416f4924f 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -6,7 +6,6 @@ using Perspex.Collections; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; using Perspex.Controls.Templates; -using Perspex.Input; using Perspex.Interactivity; using Xunit; @@ -69,6 +68,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedItem = items[1]; Assert.False(items[0].IsSelected); @@ -92,6 +92,7 @@ namespace Perspex.Controls.UnitTests.Primitives target.SelectedItem = items[1]; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); Assert.False(items[0].IsSelected); Assert.True(items[1].IsSelected); @@ -114,6 +115,7 @@ namespace Perspex.Controls.UnitTests.Primitives target.SelectedIndex = 1; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); Assert.False(items[0].IsSelected); Assert.True(items[1].IsSelected); @@ -241,6 +243,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); items.Add(new Item { IsSelected = true }); Assert.Equal(2, target.SelectedIndex); @@ -346,6 +349,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedItem = items[1]; Assert.False(items[0].IsSelected); @@ -376,6 +380,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedItem = items[1]; Assert.False(items[0].IsSelected); diff --git a/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs b/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs index 3d19e353ad..8cb736d110 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs +++ b/tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs @@ -168,6 +168,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedItems.Add(items[0]); target.SelectedItems.Add(items[1]); @@ -195,6 +196,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedItems = new PerspexList { items[0], items[1] }; Assert.True(items[0].IsSelected); @@ -219,6 +221,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedItems.Add(items[0]); target.SelectedItems.Add(items[1]); target.SelectedItems.Remove(items[1]); @@ -270,6 +273,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); target.SelectedIndex = 1; target.SelectedItems[0] = items[2]; diff --git a/tests/Perspex.Controls.UnitTests/Primitives/TabStripTests.cs b/tests/Perspex.Controls.UnitTests/Primitives/TabStripTests.cs index 6ae55f73c2..92299369b2 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/TabStripTests.cs +++ b/tests/Perspex.Controls.UnitTests/Primitives/TabStripTests.cs @@ -30,6 +30,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); var result = target.GetLogicalChildren() .OfType() @@ -55,6 +56,7 @@ namespace Perspex.Controls.UnitTests.Primitives }; target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); var result = target.GetLogicalChildren() .OfType() diff --git a/tests/Perspex.Controls.UnitTests/Primitives/TemplatedControlTests.cs b/tests/Perspex.Controls.UnitTests/Primitives/TemplatedControlTests.cs index d4d20d3d9d..178a00b5ac 100644 --- a/tests/Perspex.Controls.UnitTests/Primitives/TemplatedControlTests.cs +++ b/tests/Perspex.Controls.UnitTests/Primitives/TemplatedControlTests.cs @@ -160,42 +160,17 @@ namespace Perspex.Controls.UnitTests.Primitives } [Fact] - public void Nested_Templated_Controls_Have_Correct_TemplatedParent() + public void Nested_Templated_Control_Should_Not_Have_Template_Applied() { - var target = new TestTemplatedControl + var target = new TemplatedControl { - Template = new FuncControlTemplate(_ => - { - return new ContentControl - { - Template = new FuncControlTemplate(parent => - { - return new Border - { - Child = new ContentPresenter - { - [~ContentPresenter.ContentProperty] = parent.GetObservable(ContentControl.ContentProperty), - } - }; - }), - Content = new TextBlock - { - } - }; - }), + Template = new FuncControlTemplate(_ => new ScrollViewer()) }; target.ApplyTemplate(); - var contentControl = target.GetTemplateChildren().OfType().Single(); - var border = contentControl.GetTemplateChildren().OfType().Single(); - var presenter = contentControl.GetTemplateChildren().OfType().Single(); - var textBlock = (TextBlock)presenter.Content; - - Assert.Equal(target, contentControl.TemplatedParent); - Assert.Equal(contentControl, border.TemplatedParent); - Assert.Equal(contentControl, presenter.TemplatedParent); - Assert.Equal(target, textBlock.TemplatedParent); + var child = (ScrollViewer)target.GetVisualChildren().Single(); + Assert.Empty(child.GetVisualChildren()); } [Fact] @@ -218,11 +193,11 @@ namespace Perspex.Controls.UnitTests.Primitives return new StackPanel { Children = new Controls - { - new TextBlock { + new TextBlock + { + } } - } }; }), } @@ -236,6 +211,47 @@ namespace Perspex.Controls.UnitTests.Primitives } } + [Fact] + public void Nested_Templated_Controls_Have_Correct_TemplatedParent() + { + var target = new TestTemplatedControl + { + Template = new FuncControlTemplate(_ => + { + return new ContentControl + { + Template = new FuncControlTemplate(parent => + { + return new Border + { + Child = new ContentPresenter + { + [~ContentPresenter.ContentProperty] = parent.GetObservable(ContentControl.ContentProperty), + } + }; + }), + Content = new TextBlock + { + } + }; + }), + }; + + target.ApplyTemplate(); + + var contentControl = target.GetTemplateChildren().OfType().Single(); + contentControl.ApplyTemplate(); + + var border = contentControl.GetTemplateChildren().OfType().Single(); + var presenter = contentControl.GetTemplateChildren().OfType().Single(); + var textBlock = (TextBlock)presenter.Content; + + Assert.Equal(target, contentControl.TemplatedParent); + Assert.Equal(contentControl, border.TemplatedParent); + Assert.Equal(contentControl, presenter.TemplatedParent); + Assert.Equal(target, textBlock.TemplatedParent); + } + [Fact] public void Nested_TemplatedControls_Should_Register_With_Correct_NameScope() { @@ -245,19 +261,26 @@ namespace Perspex.Controls.UnitTests.Primitives Content = "foo" }; + var root = new TestRoot { Child = target }; target.ApplyTemplate(); var border = target.GetVisualChildren().FirstOrDefault(); Assert.IsType(border); + var scrollViewer = border.GetVisualChildren().FirstOrDefault(); Assert.IsType(scrollViewer); + ((ScrollViewer)scrollViewer).ApplyTemplate(); + var scrollContentPresenter = scrollViewer.GetVisualChildren().FirstOrDefault(); Assert.IsType(scrollContentPresenter); + ((ContentPresenter)scrollContentPresenter).UpdateChild(); + var contentPresenter = scrollContentPresenter.GetVisualChildren().FirstOrDefault(); Assert.IsType(contentPresenter); var borderNs = NameScope.GetNameScope((Control)border); var scrollContentPresenterNs = NameScope.GetNameScope((Control)scrollContentPresenter); + Assert.NotNull(borderNs); Assert.Same(scrollViewer, borderNs.Find("ScrollViewer")); Assert.Same(contentPresenter, borderNs.Find("PART_ContentPresenter")); diff --git a/tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs b/tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs index 563b270605..f7758d15d2 100644 --- a/tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs +++ b/tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs @@ -1,12 +1,9 @@ // 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 System.Linq; -using Perspex.Controls; using Perspex.Controls.Presenters; using Perspex.Controls.Primitives; using Perspex.Controls.Templates; -using Perspex.VisualTree; using Xunit; namespace Perspex.Controls.UnitTests @@ -23,28 +20,11 @@ namespace Perspex.Controls.UnitTests }; target.ApplyTemplate(); + target.Presenter.UpdateChild(); Assert.IsType(target.Presenter.Child); } - [Fact] - public void ScrollViewer_In_Template_Sets_Child_TemplatedParent() - { - var target = new ContentControl - { - Template = new FuncControlTemplate(CreateNestedTemplate), - Content = "Foo", - }; - - target.ApplyTemplate(); - - var presenter = target.GetVisualDescendents() - .OfType() - .Single(x => x.Name == "this"); - - Assert.Equal(target, presenter.TemplatedParent); - } - [Fact] public void Offset_Should_Be_Coerced_To_Viewport() { @@ -112,7 +92,7 @@ namespace Perspex.Controls.UnitTests Template = new FuncControlTemplate(CreateTemplate), Content = new ContentPresenter { - Name = "this" + Name = "PART_ContentPresenter", } }; } diff --git a/tests/Perspex.Controls.UnitTests/TabControlTests.cs b/tests/Perspex.Controls.UnitTests/TabControlTests.cs index 0f3172e715..f3d915951f 100644 --- a/tests/Perspex.Controls.UnitTests/TabControlTests.cs +++ b/tests/Perspex.Controls.UnitTests/TabControlTests.cs @@ -1,6 +1,7 @@ // 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 System; using System.Collections.ObjectModel; using System.Linq; using Perspex.Controls.Presenters; @@ -181,8 +182,7 @@ namespace Perspex.Controls.UnitTests Items = items, }; - target.ApplyTemplate(); - + ApplyTemplate(target); var carousel = (Carousel)target.Pages; var dataContext = ((TextBlock)carousel.Presenter.Panel.GetLogicalChildren().Single()).DataContext; @@ -229,7 +229,7 @@ namespace Perspex.Controls.UnitTests Items = items, }; - target.ApplyTemplate(); + ApplyTemplate(target); var result = target.TabStrip.GetLogicalChildren() .OfType() @@ -288,6 +288,17 @@ namespace Perspex.Controls.UnitTests }; } + private void ApplyTemplate(TabControl target) + { + target.ApplyTemplate(); + var carousel = (Carousel)target.Pages; + carousel.ApplyTemplate(); + carousel.Presenter.ApplyTemplate(); + var tabStrip = (TabStrip)target.TabStrip; + tabStrip.ApplyTemplate(); + tabStrip.Presenter.ApplyTemplate(); + } + private class Item { public Item(string value) diff --git a/tests/Perspex.Controls.UnitTests/TopLevelTests.cs b/tests/Perspex.Controls.UnitTests/TopLevelTests.cs index 6e8ea4c068..9e4e54608c 100644 --- a/tests/Perspex.Controls.UnitTests/TopLevelTests.cs +++ b/tests/Perspex.Controls.UnitTests/TopLevelTests.cs @@ -311,8 +311,9 @@ namespace Perspex.Controls.UnitTests target.Template = CreateTemplate(); target.Content = child; + target.ApplyTemplate(); - Assert.Throws(() => target.ApplyTemplate()); + Assert.Throws(() => target.Presenter.ApplyTemplate()); } } @@ -321,6 +322,7 @@ namespace Perspex.Controls.UnitTests return new FuncControlTemplate(x => new ContentPresenter { + Name = "PART_ContentPresenter", [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty], }); } diff --git a/tests/Perspex.Controls.UnitTests/TreeViewTests.cs b/tests/Perspex.Controls.UnitTests/TreeViewTests.cs index 9af8a15f84..8ee0d73a1e 100644 --- a/tests/Perspex.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Perspex.Controls.UnitTests/TreeViewTests.cs @@ -24,7 +24,7 @@ namespace Perspex.Controls.UnitTests DataTemplates = CreateNodeDataTemplate(), }; - target.ApplyTemplate(); + ApplyTemplates(target); Assert.Equal(new[] { "Root" }, ExtractItemHeader(target, 0)); Assert.Equal(new[] { "Child1", "Child2" }, ExtractItemHeader(target, 1)); @@ -41,7 +41,7 @@ namespace Perspex.Controls.UnitTests DataTemplates = CreateNodeDataTemplate(), }; - target.ApplyTemplate(); + ApplyTemplates(target); var container = (TreeViewItem)target.ItemContainerGenerator.Containers.Single().ContainerControl; var header = (TextBlock)container.Header; @@ -116,7 +116,7 @@ namespace Perspex.Controls.UnitTests Items = new[] { "Foo", "Bar", "Baz " }, }; - target.ApplyTemplate(); + ApplyTemplates(target); var result = target.GetLogicalChildren() .OfType() @@ -172,7 +172,7 @@ namespace Perspex.Controls.UnitTests Items = items, }; - target.ApplyTemplate(); + ApplyTemplates(target); var dataContexts = target.Presenter.Panel.Children .Cast() @@ -187,6 +187,7 @@ namespace Perspex.Controls.UnitTests private void ApplyTemplates(TreeView tree) { tree.ApplyTemplate(); + tree.Presenter.ApplyTemplate(); ApplyTemplates(tree.Presenter.Panel.Children); } @@ -196,6 +197,7 @@ namespace Perspex.Controls.UnitTests { control.Template = CreateTreeViewItemTemplate(); control.ApplyTemplate(); + control.Presenter.ApplyTemplate(); ApplyTemplates(control.Presenter.Panel.Children); } } diff --git a/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs b/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs index 6cdcd81539..a32b9ac9e4 100644 --- a/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs +++ b/tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// 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 Moq; using Perspex.Controls.Presenters; using Perspex.Controls.Templates; -using Perspex.Controls.UnitTests.Primitives; using Perspex.Input; using Perspex.Platform; using Perspex.Styling; @@ -35,6 +32,7 @@ namespace Perspex.Controls.UnitTests.Utils tl.Content = button; tl.Template = CreateWindowTemplate(); tl.ApplyTemplate(); + tl.Presenter.ApplyTemplate(); HotKeyManager.SetHotKey(button, gesture1);