diff --git a/Perspex.Controls/Control.cs b/Perspex.Controls/Control.cs
index 24c025f8b5..790021156a 100644
--- a/Perspex.Controls/Control.cs
+++ b/Perspex.Controls/Control.cs
@@ -7,11 +7,13 @@
namespace Perspex.Controls
{
using System;
+ using System.Linq;
using System.Reactive.Linq;
using Perspex.Collections;
using Perspex.Controls.Primitives;
using Perspex.Input;
using Perspex.Interactivity;
+ using Perspex.LogicalTree;
using Perspex.Rendering;
using Perspex.Styling;
using Splat;
@@ -29,7 +31,7 @@ namespace Perspex.Controls
/// - Implements to allow styling to work on the control.
/// - Implements to form part of a logical tree.
///
- public class Control : InputElement, IControl
+ public class Control : InputElement, IControl, ISetLogicalParent
{
///
/// Defines the property.
@@ -231,7 +233,6 @@ namespace Perspex.Controls
public IControl Parent
{
get { return this.GetValue(ParentProperty); }
- internal set { this.SetValue(ParentProperty, value); }
}
///
@@ -306,6 +307,55 @@ namespace Perspex.Controls
this.RaiseEvent(ev);
}
+ ///
+ /// Sets the control's logical parent.
+ ///
+ /// The parent.
+ void ISetLogicalParent.SetParent(IControl parent)
+ {
+ var old = this.Parent;
+
+ if (old != null && parent != null)
+ {
+ throw new InvalidOperationException("The Control already has a parent.");
+ }
+
+ this.SetValue(ParentProperty, parent);
+
+ if (parent != null)
+ {
+ var nameScope = parent.GetSelfAndLogicalAncestors()
+ .OfType()
+ .FirstOrDefault();
+
+ if (nameScope != null)
+ {
+ this.RegisterName(nameScope);
+
+ foreach (var descendent in this.GetLogicalDescendents().OfType())
+ {
+ descendent.RegisterName(nameScope);
+ }
+ }
+ }
+ else if (old != null)
+ {
+ var nameScope = old.GetSelfAndLogicalAncestors()
+ .OfType()
+ .FirstOrDefault();
+
+ if (nameScope != null)
+ {
+ this.UnregisterName(nameScope);
+
+ foreach (var descendent in this.GetLogicalDescendents().OfType())
+ {
+ descendent.UnregisterName(nameScope);
+ }
+ }
+ }
+ }
+
[Obsolete("Obsolete this: use properties instead")]
protected static void PseudoClass(PerspexProperty property, string className)
{
@@ -393,5 +443,29 @@ namespace Perspex.Controls
IStyler styler = Locator.Current.GetService();
styler.ApplyStyles(this);
}
+
+ ///
+ /// Registers the control with the specified name scope.
+ ///
+ /// The name scope.
+ private void RegisterName(INameScope nameScope)
+ {
+ if (!string.IsNullOrWhiteSpace(this.Name))
+ {
+ nameScope.RegisterName(this.Name, this);
+ }
+ }
+
+ ///
+ /// Unregisters the control with the specified name scope.
+ ///
+ /// The name scope.
+ private void UnregisterName(INameScope nameScope)
+ {
+ if (!string.IsNullOrWhiteSpace(this.Name))
+ {
+ nameScope.UnregisterName(this.Name);
+ }
+ }
}
}
diff --git a/Perspex.Controls/Decorator.cs b/Perspex.Controls/Decorator.cs
index 4ca080be55..bccf348d0e 100644
--- a/Perspex.Controls/Decorator.cs
+++ b/Perspex.Controls/Decorator.cs
@@ -102,14 +102,14 @@ namespace Perspex.Controls
if (oldChild != null)
{
- oldChild.Parent = null;
+ ((ISetLogicalParent)oldChild).SetParent(null);
this.RemoveVisualChild(oldChild);
}
if (newChild != null)
{
this.AddVisualChild(newChild);
- newChild.Parent = this;
+ ((ISetLogicalParent)newChild).SetParent(this);
}
this.logicalChild.SingleItem = newChild;
diff --git a/Perspex.Controls/DropDown.cs b/Perspex.Controls/DropDown.cs
index ee1a03f1a3..6897088982 100644
--- a/Perspex.Controls/DropDown.cs
+++ b/Perspex.Controls/DropDown.cs
@@ -76,7 +76,6 @@ namespace Perspex.Controls
protected override void OnTemplateApplied()
{
var container = this.GetTemplateChild("container");
- ((IItemsPanel)container).ChildLogicalParent = this;
this.logicalChildren.Source = ((ILogical)container).LogicalChildren;
}
@@ -87,12 +86,12 @@ namespace Perspex.Controls
if (control1 != null)
{
- control1.Parent = null;
+ ((ISetLogicalParent)control1).SetParent(null);
}
if (control2 != null)
{
- control2.Parent = this;
+ ((ISetLogicalParent)control2).SetParent(this);
}
}
}
diff --git a/Perspex.Controls/INameScope.cs b/Perspex.Controls/INameScope.cs
new file mode 100644
index 0000000000..a7eeb07781
--- /dev/null
+++ b/Perspex.Controls/INameScope.cs
@@ -0,0 +1,40 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2015 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Controls
+{
+ ///
+ /// Defines the interface for object which define a name scope.
+ ///
+ public interface INameScope
+ {
+ ///
+ /// Returns an object tha thas the requested name.
+ ///
+ /// The name of the object.
+ /// The named object or null if the named object was not found.
+ object FindName(string name);
+
+ ///
+ /// Registers an object with the specified name in the name scope.
+ ///
+ /// The name of the object.
+ /// The object.
+ ///
+ /// An object with the same name has already been registered.
+ ///
+ void RegisterName(string name, object o);
+
+ ///
+ /// Unregisters the specified name in the name scope.
+ ///
+ /// The name of the object.
+ ///
+ /// The name does not exist in the name scope.
+ ///
+ void UnregisterName(string name);
+ }
+}
\ No newline at end of file
diff --git a/Perspex.Controls/ISetLogicalParent.cs b/Perspex.Controls/ISetLogicalParent.cs
new file mode 100644
index 0000000000..4c91aa6bdd
--- /dev/null
+++ b/Perspex.Controls/ISetLogicalParent.cs
@@ -0,0 +1,23 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2015 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Controls
+{
+ ///
+ /// Defines an interface through which a 's logical parent can be set.
+ ///
+ ///
+ /// You should not usually need to use this interface - it is for advanced scenarios only.
+ ///
+ public interface ISetLogicalParent
+ {
+ ///
+ /// Sets the control's parent.
+ ///
+ /// The parent.
+ void SetParent(IControl parent);
+ }
+}
\ No newline at end of file
diff --git a/Perspex.Controls/Panel.cs b/Perspex.Controls/Panel.cs
index 7496d3fd6f..26d8825ec4 100644
--- a/Perspex.Controls/Panel.cs
+++ b/Perspex.Controls/Panel.cs
@@ -122,7 +122,7 @@ namespace Perspex.Controls
{
foreach (var control in controls)
{
- control.Parent = null;
+ ((ISetLogicalParent)control).SetParent(null);
}
}
@@ -132,9 +132,11 @@ namespace Perspex.Controls
/// The controls.
private void SetLogicalParent(IEnumerable controls)
{
+ var parent = this.childLogicalParent as Control;
+
foreach (var control in controls)
{
- control.Parent = this.childLogicalParent as Control;
+ ((ISetLogicalParent)control).SetParent(parent);
}
}
diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj
index cc98e7f0e4..328b44d18f 100644
--- a/Perspex.Controls/Perspex.Controls.csproj
+++ b/Perspex.Controls/Perspex.Controls.csproj
@@ -37,6 +37,8 @@
+
+
diff --git a/Perspex.Controls/Popup.cs b/Perspex.Controls/Popup.cs
index 746ef04278..41cdc126b9 100644
--- a/Perspex.Controls/Popup.cs
+++ b/Perspex.Controls/Popup.cs
@@ -185,7 +185,6 @@ namespace Perspex.Controls
{
this.popupRoot = new PopupRoot(this.DependencyResolver)
{
- Parent = this,
[~PopupRoot.ContentProperty] = this[~ChildProperty],
[~PopupRoot.WidthProperty] = this[~WidthProperty],
[~PopupRoot.HeightProperty] = this[~HeightProperty],
@@ -194,6 +193,8 @@ namespace Perspex.Controls
[~PopupRoot.MinHeightProperty] = this[~MinHeightProperty],
[~PopupRoot.MaxHeightProperty] = this[~MaxHeightProperty],
};
+
+ ((ISetLogicalParent)this.popupRoot).SetParent(this);
}
this.popupRoot.SetPosition(this.GetPosition());
@@ -279,12 +280,12 @@ namespace Perspex.Controls
{
if (values.Item1 != null)
{
- values.Item1.Parent = null;
+ ((ISetLogicalParent)values.Item1).SetParent(null);
}
if (values.Item2 != null)
{
- values.Item2.Parent = this;
+ ((ISetLogicalParent)values.Item2).SetParent(this);
}
this.logicalChild.SingleItem = values.Item2;
diff --git a/Perspex.Controls/Presenters/ContentPresenter.cs b/Perspex.Controls/Presenters/ContentPresenter.cs
index 5556be8a98..aaf110c0eb 100644
--- a/Perspex.Controls/Presenters/ContentPresenter.cs
+++ b/Perspex.Controls/Presenters/ContentPresenter.cs
@@ -87,7 +87,11 @@ namespace Perspex.Controls.Presenters
if (content != null)
{
result = this.MaterializeDataTemplate(content);
- result.Parent = this.TemplatedParent as Control;
+
+ if (result.Parent == null)
+ {
+ ((ISetLogicalParent)result).SetParent(this.TemplatedParent as Control);
+ }
var templatedParent = this.TemplatedParent as TemplatedControl;
diff --git a/Perspex.Controls/Primitives/AdornerDecorator.cs b/Perspex.Controls/Primitives/AdornerDecorator.cs
index 4fb129063c..b877118f5d 100644
--- a/Perspex.Controls/Primitives/AdornerDecorator.cs
+++ b/Perspex.Controls/Primitives/AdornerDecorator.cs
@@ -11,7 +11,7 @@ namespace Perspex.Controls.Primitives
public AdornerDecorator()
{
this.AdornerLayer = new AdornerLayer();
- this.AdornerLayer.Parent = this;
+ ((ISetLogicalParent)this.AdornerLayer).SetParent(this);
this.AdornerLayer.ZIndex = int.MaxValue;
this.AddVisualChild(this.AdornerLayer);
}
diff --git a/Perspex.Controls/Primitives/TemplatedControl.cs b/Perspex.Controls/Primitives/TemplatedControl.cs
index 0cf46790c9..6e7fe0b822 100644
--- a/Perspex.Controls/Primitives/TemplatedControl.cs
+++ b/Perspex.Controls/Primitives/TemplatedControl.cs
@@ -140,7 +140,7 @@ namespace Perspex.Controls.Primitives
var child = this.Template.Build(this);
this.SetTemplatedParent(child);
this.AddVisualChild(child);
- child.Parent = this;
+ ((ISetLogicalParent)child).SetParent(this);
foreach (var i in this.GetTemplateChildren())
{
diff --git a/Perspex.Controls/ToolTip.cs b/Perspex.Controls/ToolTip.cs
index 91fd3c6d82..c9a6753327 100644
--- a/Perspex.Controls/ToolTip.cs
+++ b/Perspex.Controls/ToolTip.cs
@@ -117,7 +117,7 @@ namespace Perspex.Controls
var cp = MouseDevice.Instance.GetPosition(control);
var position = control.PointToScreen(cp) + new Vector(0, 22);
- popup.Parent = control;
+ ((ISetLogicalParent)popup).SetParent(control);
((ToolTip)popup.Content).Content = GetTip(control);
popup.SetPosition(position);
popup.Show();