From 8d2006c96894679266f8632c8be177356599a69e Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 28 Jan 2015 12:23:38 +0100 Subject: [PATCH] Make dropdown close on click. --- Perspex.Controls/Popup.cs | 35 +++++++++++++++---------- Perspex.Input/InputElement.cs | 9 +++++++ Perspex.Input/MouseDevice.cs | 10 ++++--- Perspex.Interactivity/Interactive.cs | 2 +- Perspex.Themes.Default/DropDownStyle.cs | 3 ++- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/Perspex.Controls/Popup.cs b/Perspex.Controls/Popup.cs index 9acd445c6a..ef4b4c2856 100644 --- a/Perspex.Controls/Popup.cs +++ b/Perspex.Controls/Popup.cs @@ -24,9 +24,9 @@ namespace Perspex.Controls public static readonly PerspexProperty StaysOpenProperty = PerspexProperty.Register("StaysOpen", true); - private PopupRoot root; + private PopupRoot popupRoot; - private Window window; + private TopLevel topLevel; static Popup() { @@ -73,36 +73,43 @@ namespace Perspex.Controls public void Open() { - if (this.root == null) + if (this.popupRoot == null) { - this.root = new PopupRoot(); - this.root.Parent = this; - this.root[~PopupRoot.ContentProperty] = this[~ChildProperty]; - this.root.Deactivated += this.RootDeactivated; + this.popupRoot = new PopupRoot(); + this.popupRoot.Parent = this; + this.popupRoot[~PopupRoot.ContentProperty] = this[~ChildProperty]; } - this.root.SetPosition(this.GetPosition()); - this.root.Show(); + this.popupRoot.SetPosition(this.GetPosition()); + this.popupRoot.PreviewPointerPressed += this.MaybeClose; + this.topLevel.PreviewPointerPressed += this.MaybeClose; + this.topLevel.Deactivated += this.MaybeClose; + this.popupRoot.Show(); } public void Close() { - if (this.root != null) + if (this.popupRoot != null) { - this.root.Hide(); + this.popupRoot.PreviewPointerPressed -= this.MaybeClose; + this.topLevel.PreviewPointerPressed -= this.MaybeClose; + this.topLevel.Deactivated -= this.MaybeClose; + this.popupRoot.Hide(); } + + this.IsOpen = false; } protected override void OnAttachedToVisualTree(IRenderRoot root) { base.OnAttachedToVisualTree(root); - this.window = root as Window; + this.topLevel = root as TopLevel; } protected override void OnDetachedFromVisualTree(IRenderRoot oldRoot) { base.OnDetachedFromVisualTree(oldRoot); - this.window = null; + this.topLevel = null; } private Point GetPosition() @@ -117,7 +124,7 @@ namespace Perspex.Controls } } - private void RootDeactivated(object sender, EventArgs e) + private void MaybeClose(object sender, EventArgs e) { if (!this.StaysOpen) { diff --git a/Perspex.Input/InputElement.cs b/Perspex.Input/InputElement.cs index 263d9579d5..ec0a403ab9 100644 --- a/Perspex.Input/InputElement.cs +++ b/Perspex.Input/InputElement.cs @@ -41,6 +41,9 @@ namespace Perspex.Input public static readonly RoutedEvent PreviewKeyDownEvent = RoutedEvent.Register("PreviewKeyDown", RoutingStrategy.Tunnel); + public static readonly RoutedEvent PreviewPointerPressedEvent = + RoutedEvent.Register("PreviewPointerPressed", RoutingStrategy.Tunnel); + public static readonly RoutedEvent PointerEnterEvent = RoutedEvent.Register("PointerEnter", RoutingStrategy.Direct); @@ -99,6 +102,12 @@ namespace Perspex.Input remove { this.RemoveHandler(PreviewKeyDownEvent, value); } } + public event EventHandler PreviewPointerPressed + { + add { this.AddHandler(PreviewPointerPressedEvent, value); } + remove { this.RemoveHandler(PreviewPointerPressedEvent, value); } + } + public event EventHandler PointerEnter { add { this.AddHandler(PointerEnterEvent, value); } diff --git a/Perspex.Input/MouseDevice.cs b/Perspex.Input/MouseDevice.cs index f761bbb02f..db1e7b7988 100644 --- a/Perspex.Input/MouseDevice.cs +++ b/Perspex.Input/MouseDevice.cs @@ -128,14 +128,18 @@ namespace Perspex.Input this.lastClickRect = new Rect(p, new Size()) .Inflate(new Thickness(settings.DoubleClickSize.Width / 2, settings.DoubleClickSize.Height / 2)); - source.RaiseEvent(new PointerPressEventArgs + var e = new PointerPressEventArgs { Device = this, - RoutedEvent = InputElement.PointerPressedEvent, + RoutedEvent = InputElement.PreviewPointerPressedEvent, OriginalSource = source, Source = source, ClickCount = this.clickCount, - }); + }; + + source.RaiseEvent(e); + e.RoutedEvent = InputElement.PointerPressedEvent; + source.RaiseEvent(e); } IInputElement focusable = this.GetFocusable(hit); diff --git a/Perspex.Interactivity/Interactive.cs b/Perspex.Interactivity/Interactive.cs index 5a6426ddba..064074c6ed 100644 --- a/Perspex.Interactivity/Interactive.cs +++ b/Perspex.Interactivity/Interactive.cs @@ -120,7 +120,7 @@ namespace Perspex.Interactivity if (this.eventHandlers.TryGetValue(e.RoutedEvent, out delegates)) { - foreach (Delegate handler in delegates) + foreach (Delegate handler in delegates.ToList()) { handler.DynamicInvoke(this, e); } diff --git a/Perspex.Themes.Default/DropDownStyle.cs b/Perspex.Themes.Default/DropDownStyle.cs index 7041cdd0ae..5fca90107c 100644 --- a/Perspex.Themes.Default/DropDownStyle.cs +++ b/Perspex.Themes.Default/DropDownStyle.cs @@ -87,7 +87,8 @@ namespace Perspex.Themes.Default [~~ListBox.SelectedItemProperty] = control[~~DropDown.SelectedItemProperty], }, PlacementTarget = control, - [~Popup.IsOpenProperty] = control[~DropDown.IsDropDownOpenProperty], + StaysOpen = false, + [~~Popup.IsOpenProperty] = control[~~DropDown.IsDropDownOpenProperty], } }, },