Browse Source

Manipulate logical parent thru ISetLogicalParent.

Ported from ideas branch. Also includes beginnings of INameScope
support, though nothing implements this interface yet.
pull/63/head
Steven Kirk 11 years ago
parent
commit
9a9132c42b
  1. 78
      Perspex.Controls/Control.cs
  2. 4
      Perspex.Controls/Decorator.cs
  3. 5
      Perspex.Controls/DropDown.cs
  4. 40
      Perspex.Controls/INameScope.cs
  5. 23
      Perspex.Controls/ISetLogicalParent.cs
  6. 6
      Perspex.Controls/Panel.cs
  7. 2
      Perspex.Controls/Perspex.Controls.csproj
  8. 7
      Perspex.Controls/Popup.cs
  9. 6
      Perspex.Controls/Presenters/ContentPresenter.cs
  10. 2
      Perspex.Controls/Primitives/AdornerDecorator.cs
  11. 2
      Perspex.Controls/Primitives/TemplatedControl.cs
  12. 2
      Perspex.Controls/ToolTip.cs

78
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 <see cref="IStyleable"/> to allow styling to work on the control.
/// - Implements <see cref="ILogical"/> to form part of a logical tree.
/// </remarks>
public class Control : InputElement, IControl
public class Control : InputElement, IControl, ISetLogicalParent
{
/// <summary>
/// Defines the <see cref="DataContext"/> property.
@ -231,7 +233,6 @@ namespace Perspex.Controls
public IControl Parent
{
get { return this.GetValue(ParentProperty); }
internal set { this.SetValue(ParentProperty, value); }
}
/// <summary>
@ -306,6 +307,55 @@ namespace Perspex.Controls
this.RaiseEvent(ev);
}
/// <summary>
/// Sets the control's logical parent.
/// </summary>
/// <param name="parent">The parent.</param>
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<INameScope>()
.FirstOrDefault();
if (nameScope != null)
{
this.RegisterName(nameScope);
foreach (var descendent in this.GetLogicalDescendents().OfType<Control>())
{
descendent.RegisterName(nameScope);
}
}
}
else if (old != null)
{
var nameScope = old.GetSelfAndLogicalAncestors()
.OfType<INameScope>()
.FirstOrDefault();
if (nameScope != null)
{
this.UnregisterName(nameScope);
foreach (var descendent in this.GetLogicalDescendents().OfType<Control>())
{
descendent.UnregisterName(nameScope);
}
}
}
}
[Obsolete("Obsolete this: use properties instead")]
protected static void PseudoClass(PerspexProperty<bool> property, string className)
{
@ -393,5 +443,29 @@ namespace Perspex.Controls
IStyler styler = Locator.Current.GetService<IStyler>();
styler.ApplyStyles(this);
}
/// <summary>
/// Registers the control with the specified name scope.
/// </summary>
/// <param name="nameScope">The name scope.</param>
private void RegisterName(INameScope nameScope)
{
if (!string.IsNullOrWhiteSpace(this.Name))
{
nameScope.RegisterName(this.Name, this);
}
}
/// <summary>
/// Unregisters the control with the specified name scope.
/// </summary>
/// <param name="nameScope">The name scope.</param>
private void UnregisterName(INameScope nameScope)
{
if (!string.IsNullOrWhiteSpace(this.Name))
{
nameScope.UnregisterName(this.Name);
}
}
}
}

4
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;

5
Perspex.Controls/DropDown.cs

@ -76,7 +76,6 @@ namespace Perspex.Controls
protected override void OnTemplateApplied()
{
var container = this.GetTemplateChild<Panel>("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);
}
}
}

40
Perspex.Controls/INameScope.cs

@ -0,0 +1,40 @@
// -----------------------------------------------------------------------
// <copyright file="INameScope.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls
{
/// <summary>
/// Defines the interface for object which define a name scope.
/// </summary>
public interface INameScope
{
/// <summary>
/// Returns an object tha thas the requested name.
/// </summary>
/// <param name="name">The name of the object.</param>
/// <returns>The named object or null if the named object was not found.</returns>
object FindName(string name);
/// <summary>
/// Registers an object with the specified name in the name scope.
/// </summary>
/// <param name="name">The name of the object.</param>
/// <param name="o">The object.</param>
/// <exception cref="ArgumentException">
/// An object with the same name has already been registered.
/// </exception>
void RegisterName(string name, object o);
/// <summary>
/// Unregisters the specified name in the name scope.
/// </summary>
/// <param name="name">The name of the object.</param>
/// <exception cref="ArgumentException">
/// The name does not exist in the name scope.
/// </exception>
void UnregisterName(string name);
}
}

23
Perspex.Controls/ISetLogicalParent.cs

@ -0,0 +1,23 @@
// -----------------------------------------------------------------------
// <copyright file="ISetLogicalParent.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls
{
/// <summary>
/// Defines an interface through which a <see cref="Control"/>'s logical parent can be set.
/// </summary>
/// <remarks>
/// You should not usually need to use this interface - it is for advanced scenarios only.
/// </remarks>
public interface ISetLogicalParent
{
/// <summary>
/// Sets the control's parent.
/// </summary>
/// <param name="parent">The parent.</param>
void SetParent(IControl parent);
}
}

6
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
/// <param name="controls">The controls.</param>
private void SetLogicalParent(IEnumerable<Control> controls)
{
var parent = this.childLogicalParent as Control;
foreach (var control in controls)
{
control.Parent = this.childLogicalParent as Control;
((ISetLogicalParent)control).SetParent(parent);
}
}

2
Perspex.Controls/Perspex.Controls.csproj

@ -37,6 +37,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="IControl.cs" />
<Compile Include="INameScope.cs" />
<Compile Include="ISetLogicalParent.cs" />
<Compile Include="MenuItemAccessKeyHandler.cs" />
<Compile Include="Parsers\GridLengthsParser.cs" />
<Compile Include="Primitives\AccessText.cs" />

7
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;

6
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;

2
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);
}

2
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())
{

2
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();

Loading…
Cancel
Save