diff --git a/Perspex.Controls/Popup.cs b/Perspex.Controls/Popup.cs index d7aedb3a89..2eb886f5a3 100644 --- a/Perspex.Controls/Popup.cs +++ b/Perspex.Controls/Popup.cs @@ -12,90 +12,159 @@ namespace Perspex.Controls using Perspex.Rendering; using Perspex.VisualTree; + /// + /// Displays a popup window. + /// public class Popup : Control, ILogical, IVisualTreeHost { + /// + /// Defines the property. + /// public static readonly PerspexProperty ChildProperty = - PerspexProperty.Register("Child"); + PerspexProperty.Register(nameof(Child)); + /// + /// Defines the property. + /// public static readonly PerspexProperty IsOpenProperty = - PerspexProperty.Register("IsOpen"); + PerspexProperty.Register(nameof(IsOpen)); + /// + /// Defines the property. + /// public static readonly PerspexProperty PlacementModeProperty = - PerspexProperty.Register("PlacementMode", defaultValue: PlacementMode.Bottom); + PerspexProperty.Register(nameof(PlacementMode), defaultValue: PlacementMode.Bottom); + /// + /// Defines the property. + /// public static readonly PerspexProperty PlacementTargetProperty = - PerspexProperty.Register("PlacementTarget"); + PerspexProperty.Register(nameof(PlacementTarget)); + /// + /// Defines the property. + /// public static readonly PerspexProperty StaysOpenProperty = - PerspexProperty.Register("StaysOpen", true); + PerspexProperty.Register(nameof(StaysOpen), true); + /// + /// The root of the popup. + /// private PopupRoot popupRoot; + /// + /// The top level control of the Popup's visual tree. + /// private TopLevel topLevel; + /// + /// The popup's logical child. + /// private PerspexSingleItemList logicalChild = new PerspexSingleItemList(); + /// + /// Initializes static members of the class. + /// static Popup() { - IsOpenProperty.Changed.Subscribe(IsOpenChanged); + IsOpenProperty.Changed.AddClassHandler(x => x.IsOpenChanged); } + /// + /// Initializes a new instance of the class. + /// public Popup() { - this.GetObservableWithHistory(ChildProperty).Subscribe(ChildChanged); + this.GetObservableWithHistory(ChildProperty).Subscribe(this.ChildChanged); } + /// + /// Raised when the popup closes. + /// public event EventHandler Closed; + /// + /// Raised when the popup opens. + /// public event EventHandler Opened; + /// + /// Raised when the popup root has been created, but before it has been shown. + /// public event EventHandler PopupRootCreated; + /// + /// Gets or sets the control to display in the popup. + /// public Control Child { get { return this.GetValue(ChildProperty); } set { this.SetValue(ChildProperty, value); } } + /// + /// Gets or sets a value indicating whether the popup is currently open. + /// public bool IsOpen { get { return this.GetValue(IsOpenProperty); } set { this.SetValue(IsOpenProperty, value); } } + /// + /// Gets or sets the placement mode of the popup in relation to the . + /// public PlacementMode PlacementMode { get { return this.GetValue(PlacementModeProperty); } set { this.SetValue(PlacementModeProperty, value); } } + /// + /// Gets or sets the control that is used to determine the popup's position. + /// public Control PlacementTarget { get { return this.GetValue(PlacementTargetProperty); } set { this.SetValue(PlacementTargetProperty, value); } } + /// + /// Gets the root of the popup window. + /// public PopupRoot PopupRoot { get { return this.popupRoot; } } + /// + /// Gets or sets a value indicating whether the popup should stay open when the popup loses focus. + /// public bool StaysOpen { get { return this.GetValue(StaysOpenProperty); } set { this.SetValue(StaysOpenProperty, value); } } + /// + /// Gets the logical children of the popup. + /// IPerspexReadOnlyList ILogical.LogicalChildren { get { return this.logicalChild; } } + /// + /// Gets the root of the popup window. + /// IVisual IVisualTreeHost.Root { get { return this.popupRoot; } } + /// + /// Opens the popup. + /// public void Open() { if (this.popupRoot == null) @@ -125,6 +194,9 @@ namespace Perspex.Controls this.Opened?.Invoke(this, EventArgs.Empty); } + /// + /// Closes the popup. + /// public void Close() { if (this.popupRoot != null) @@ -139,40 +211,56 @@ namespace Perspex.Controls this.Closed?.Invoke(this, EventArgs.Empty); } + /// + /// Measures the control. + /// + /// The available size for the control. + /// A size of 0,0 as Popup itself takes up no space. protected override Size MeasureCore(Size availableSize) { return new Size(); } + /// + /// Called when the control is added to the visual tree. + /// + /// THe root of the visual tree. protected override void OnAttachedToVisualTree(IRenderRoot root) { base.OnAttachedToVisualTree(root); this.topLevel = root as TopLevel; } - protected override void OnDetachedFromVisualTree(IRenderRoot oldRoot) + /// + /// Called when the control is removed to the visual tree. + /// + /// THe root of the visual tree. + protected override void OnDetachedFromVisualTree(IRenderRoot root) { - base.OnDetachedFromVisualTree(oldRoot); + base.OnDetachedFromVisualTree(root); this.topLevel = null; } - private static void IsOpenChanged(PerspexPropertyChangedEventArgs e) + /// + /// Called when the property changes. + /// + /// The event args. + 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(); } } + /// + /// Called when the property changes. + /// + /// The old and new values. private void ChildChanged(Tuple values) { if (values.Item1 != null) @@ -188,6 +276,10 @@ namespace Perspex.Controls this.logicalChild.SingleItem = values.Item2; } + /// + /// Gets the position for the popup based on the placement properties. + /// + /// The popup's position in screen coordinates. private Point GetPosition() { var target = this.PlacementTarget ?? this.GetVisualParent(); @@ -215,6 +307,12 @@ namespace Perspex.Controls } } + /// + /// Conditionally closes the popup in response to an event, based on the value of the + /// property. + /// + /// The event sender. + /// The event args. private void MaybeClose(object sender, EventArgs e) { if (!this.StaysOpen) diff --git a/Perspex.Controls/PopupRoot.cs b/Perspex.Controls/PopupRoot.cs index 05309e4647..ec6cc28b8e 100644 --- a/Perspex.Controls/PopupRoot.cs +++ b/Perspex.Controls/PopupRoot.cs @@ -12,40 +12,68 @@ namespace Perspex.Controls using Perspex.Platform; using Splat; + /// + /// The root window of a . + /// public class PopupRoot : TopLevel, IInteractive { + /// + /// Initializes static members of the class. + /// static PopupRoot() { BackgroundProperty.OverrideDefaultValue(typeof(PopupRoot), Brushes.White); } + /// + /// Initializes a new instance of the class. + /// public PopupRoot() : base(Locator.Current.GetService()) { this.GetObservable(ParentProperty).Subscribe(x => this.InheritanceParent = x); } + /// + /// Gets the platform-specific window implementation. + /// public new IPopupImpl PlatformImpl { get { return (IPopupImpl)base.PlatformImpl; } } + /// + /// Gets the parent control in the event route. + /// + /// + /// Popup events are passed to their parent window. This facilitates this. + /// IInteractive IInteractive.InteractiveParent { get { return this.Parent; } } + /// + /// Sets the position of the popup in screen coordinates. + /// + /// The position. public void SetPosition(Point p) { this.PlatformImpl.SetPosition(p); } + /// + /// Hides the popup. + /// public void Hide() { this.PlatformImpl.Hide(); this.IsVisible = false; } + /// + /// Shows the popup. + /// public void Show() { this.PlatformImpl.Show();