Browse Source

Documented Popup/PopupRoot.

pull/58/head
Steven Kirk 11 years ago
parent
commit
cb38875f82
  1. 140
      Perspex.Controls/Popup.cs
  2. 28
      Perspex.Controls/PopupRoot.cs

140
Perspex.Controls/Popup.cs

@ -12,90 +12,159 @@ namespace Perspex.Controls
using Perspex.Rendering;
using Perspex.VisualTree;
/// <summary>
/// Displays a popup window.
/// </summary>
public class Popup : Control, ILogical, IVisualTreeHost
{
/// <summary>
/// Defines the <see cref="Child"/> property.
/// </summary>
public static readonly PerspexProperty<Control> ChildProperty =
PerspexProperty.Register<Popup, Control>("Child");
PerspexProperty.Register<Popup, Control>(nameof(Child));
/// <summary>
/// Defines the <see cref="IsOpen"/> property.
/// </summary>
public static readonly PerspexProperty<bool> IsOpenProperty =
PerspexProperty.Register<Popup, bool>("IsOpen");
PerspexProperty.Register<Popup, bool>(nameof(IsOpen));
/// <summary>
/// Defines the <see cref="PlacementMode"/> property.
/// </summary>
public static readonly PerspexProperty<PlacementMode> PlacementModeProperty =
PerspexProperty.Register<Popup, PlacementMode>("PlacementMode", defaultValue: PlacementMode.Bottom);
PerspexProperty.Register<Popup, PlacementMode>(nameof(PlacementMode), defaultValue: PlacementMode.Bottom);
/// <summary>
/// Defines the <see cref="PlacementTarget"/> property.
/// </summary>
public static readonly PerspexProperty<Control> PlacementTargetProperty =
PerspexProperty.Register<Popup, Control>("PlacementTarget");
PerspexProperty.Register<Popup, Control>(nameof(PlacementTarget));
/// <summary>
/// Defines the <see cref="StaysOpen"/> property.
/// </summary>
public static readonly PerspexProperty<bool> StaysOpenProperty =
PerspexProperty.Register<Popup, bool>("StaysOpen", true);
PerspexProperty.Register<Popup, bool>(nameof(StaysOpen), true);
/// <summary>
/// The root of the popup.
/// </summary>
private PopupRoot popupRoot;
/// <summary>
/// The top level control of the Popup's visual tree.
/// </summary>
private TopLevel topLevel;
/// <summary>
/// The popup's logical child.
/// </summary>
private PerspexSingleItemList<ILogical> logicalChild = new PerspexSingleItemList<ILogical>();
/// <summary>
/// Initializes static members of the <see cref="Popup"/> class.
/// </summary>
static Popup()
{
IsOpenProperty.Changed.Subscribe(IsOpenChanged);
IsOpenProperty.Changed.AddClassHandler<Popup>(x => x.IsOpenChanged);
}
/// <summary>
/// Initializes a new instance of the <see cref="Popup"/> class.
/// </summary>
public Popup()
{
this.GetObservableWithHistory(ChildProperty).Subscribe(ChildChanged);
this.GetObservableWithHistory(ChildProperty).Subscribe(this.ChildChanged);
}
/// <summary>
/// Raised when the popup closes.
/// </summary>
public event EventHandler Closed;
/// <summary>
/// Raised when the popup opens.
/// </summary>
public event EventHandler Opened;
/// <summary>
/// Raised when the popup root has been created, but before it has been shown.
/// </summary>
public event EventHandler PopupRootCreated;
/// <summary>
/// Gets or sets the control to display in the popup.
/// </summary>
public Control Child
{
get { return this.GetValue(ChildProperty); }
set { this.SetValue(ChildProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating whether the popup is currently open.
/// </summary>
public bool IsOpen
{
get { return this.GetValue(IsOpenProperty); }
set { this.SetValue(IsOpenProperty, value); }
}
/// <summary>
/// Gets or sets the placement mode of the popup in relation to the <see cref="PlacementTarget"/>.
/// </summary>
public PlacementMode PlacementMode
{
get { return this.GetValue(PlacementModeProperty); }
set { this.SetValue(PlacementModeProperty, value); }
}
/// <summary>
/// Gets or sets the control that is used to determine the popup's position.
/// </summary>
public Control PlacementTarget
{
get { return this.GetValue(PlacementTargetProperty); }
set { this.SetValue(PlacementTargetProperty, value); }
}
/// <summary>
/// Gets the root of the popup window.
/// </summary>
public PopupRoot PopupRoot
{
get { return this.popupRoot; }
}
/// <summary>
/// Gets or sets a value indicating whether the popup should stay open when the popup loses focus.
/// </summary>
public bool StaysOpen
{
get { return this.GetValue(StaysOpenProperty); }
set { this.SetValue(StaysOpenProperty, value); }
}
/// <summary>
/// Gets the logical children of the popup.
/// </summary>
IPerspexReadOnlyList<ILogical> ILogical.LogicalChildren
{
get { return this.logicalChild; }
}
/// <summary>
/// Gets the root of the popup window.
/// </summary>
IVisual IVisualTreeHost.Root
{
get { return this.popupRoot; }
}
/// <summary>
/// Opens the popup.
/// </summary>
public void Open()
{
if (this.popupRoot == null)
@ -125,6 +194,9 @@ namespace Perspex.Controls
this.Opened?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Closes the popup.
/// </summary>
public void Close()
{
if (this.popupRoot != null)
@ -139,40 +211,56 @@ namespace Perspex.Controls
this.Closed?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Measures the control.
/// </summary>
/// <param name="availableSize">The available size for the control.</param>
/// <returns>A size of 0,0 as Popup itself takes up no space.</returns>
protected override Size MeasureCore(Size availableSize)
{
return new Size();
}
/// <summary>
/// Called when the control is added to the visual tree.
/// </summary>
/// <param name="root">THe root of the visual tree.</param>
protected override void OnAttachedToVisualTree(IRenderRoot root)
{
base.OnAttachedToVisualTree(root);
this.topLevel = root as TopLevel;
}
protected override void OnDetachedFromVisualTree(IRenderRoot oldRoot)
/// <summary>
/// Called when the control is removed to the visual tree.
/// </summary>
/// <param name="root">THe root of the visual tree.</param>
protected override void OnDetachedFromVisualTree(IRenderRoot root)
{
base.OnDetachedFromVisualTree(oldRoot);
base.OnDetachedFromVisualTree(root);
this.topLevel = null;
}
private static void IsOpenChanged(PerspexPropertyChangedEventArgs e)
/// <summary>
/// Called when the <see cref="IsOpen"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private void IsOpenChanged(PerspexPropertyChangedEventArgs e)
{
Popup popup = e.Sender as Popup;
if (popup != null)
if ((bool)e.NewValue)
{
if ((bool)e.NewValue)
{
popup.Open();
}
else
{
popup.Close();
}
this.Open();
}
else
{
this.Close();
}
}
/// <summary>
/// Called when the <see cref="Child"/> property changes.
/// </summary>
/// <param name="values">The old and new values.</param>
private void ChildChanged(Tuple<Control, Control> values)
{
if (values.Item1 != null)
@ -188,6 +276,10 @@ namespace Perspex.Controls
this.logicalChild.SingleItem = values.Item2;
}
/// <summary>
/// Gets the position for the popup based on the placement properties.
/// </summary>
/// <returns>The popup's position in screen coordinates.</returns>
private Point GetPosition()
{
var target = this.PlacementTarget ?? this.GetVisualParent<Control>();
@ -215,6 +307,12 @@ namespace Perspex.Controls
}
}
/// <summary>
/// Conditionally closes the popup in response to an event, based on the value of the
/// <see cref="StaysOpen"/> property.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void MaybeClose(object sender, EventArgs e)
{
if (!this.StaysOpen)

28
Perspex.Controls/PopupRoot.cs

@ -12,40 +12,68 @@ namespace Perspex.Controls
using Perspex.Platform;
using Splat;
/// <summary>
/// The root window of a <see cref="Popup"/>.
/// </summary>
public class PopupRoot : TopLevel, IInteractive
{
/// <summary>
/// Initializes static members of the <see cref="PopupRoot"/> class.
/// </summary>
static PopupRoot()
{
BackgroundProperty.OverrideDefaultValue(typeof(PopupRoot), Brushes.White);
}
/// <summary>
/// Initializes a new instance of the <see cref="PopupRoot"/> class.
/// </summary>
public PopupRoot()
: base(Locator.Current.GetService<IPopupImpl>())
{
this.GetObservable(ParentProperty).Subscribe(x => this.InheritanceParent = x);
}
/// <summary>
/// Gets the platform-specific window implementation.
/// </summary>
public new IPopupImpl PlatformImpl
{
get { return (IPopupImpl)base.PlatformImpl; }
}
/// <summary>
/// Gets the parent control in the event route.
/// </summary>
/// <remarks>
/// Popup events are passed to their parent window. This facilitates this.
/// </remarks>
IInteractive IInteractive.InteractiveParent
{
get { return this.Parent; }
}
/// <summary>
/// Sets the position of the popup in screen coordinates.
/// </summary>
/// <param name="p">The position.</param>
public void SetPosition(Point p)
{
this.PlatformImpl.SetPosition(p);
}
/// <summary>
/// Hides the popup.
/// </summary>
public void Hide()
{
this.PlatformImpl.Hide();
this.IsVisible = false;
}
/// <summary>
/// Shows the popup.
/// </summary>
public void Show()
{
this.PlatformImpl.Show();

Loading…
Cancel
Save