From 5b5a83f8d1e78913b60bde737cba88bbaca9b42f Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Tue, 8 Oct 2019 19:03:50 +0200 Subject: [PATCH 01/30] Adds an abstraction with IPropertyGrid --- .../MacPropertyGrid.cs | 17 +- .../PropertyPad.cs | 151 +++++++++++++----- .../IPropertyGrid.cs | 2 + .../PropertyGrid.cs | 4 +- 4 files changed, 121 insertions(+), 53 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 747eeeade9b..fc2f88a50d1 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -39,7 +39,7 @@ namespace MonoDevelop.DesignerSupport { - class MacPropertyGrid : NSView, IPropertyGrid + class MacPropertyGrid : NSView { readonly MacPropertyEditorPanel propertyEditorPanel; ComponentModelEditorProvider editorProvider; @@ -97,21 +97,6 @@ public void SetCurrentObject (object lastComponent, object [] propertyProviders) } } - public void Populate (bool saveEditSession) - { - //not implemented - } - - public void SetToolbarProvider (Components.PropertyGrid.PropertyGrid.IToolbarProvider toolbarProvider) - { - //not implemented - } - - public void OnPadContentShown () - { - //not implemented - } - protected override void Dispose (bool disposing) { if (disposing) { diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs index b2f18145e37..88c39408b8e 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs @@ -45,17 +45,106 @@ namespace MonoDevelop.DesignerSupport { + class PropertyMacHostWidget : IPropertyGrid + { + readonly GtkNSViewHost host; + readonly MacPropertyGrid view; + + public bool IsGridEditing => view.IsEditing; + + public event EventHandler PropertyGridChanged; + + public Widget Widget => host; + + public PropertyMacHostWidget () + { + view = new MacPropertyGrid (); + host = new GtkNSViewHost (view); + } + + public void SetCurrentObject (object obj, object [] propertyProviders) + => view.SetCurrentObject (obj, propertyProviders); + + public void BlankPad () + => view.BlankPad (); + + public void Dispose () + => view.Dispose (); + + public void Hide () => view.Hidden = true; + public void Show () => view.Hidden = false; + + public void OnPadContentShown () + { + //not implemented; + } + + public void PopulateGrid (bool saveEditSession) + { + //view.SetCurrentObject (obj, propertyProviders); + } + + public void SetToolbarProvider (object toolbarProvider) + { + //not implemented; + } + } + + public interface IPropertyGrid : IPropertyPad + { + void Hide (); + void Show (); + + void SetToolbarProvider (object toolbarProvider); + + Gtk.Widget Widget { get; } + } + + class PropertyGridWrapper : IPropertyGrid + { + public bool IsGridEditing => nativeWidget.IsGridEditing; + + public event EventHandler PropertyGridChanged; + + public Gtk.Widget Widget => nativeWidget.Widget; + + IPropertyGrid nativeWidget; + + public PropertyGridWrapper (IPropertyGrid splitterWidget) + { + nativeWidget = splitterWidget; + } + + public void BlankPad () + => nativeWidget.BlankPad (); + + public void PopulateGrid (bool saveEditSession) => + nativeWidget.PopulateGrid (saveEditSession); + + public void SetCurrentObject (object lastComponent, object [] propertyProviders) + => nativeWidget.SetCurrentObject (lastComponent, propertyProviders); + + public void Show () => nativeWidget.Show (); + public void Hide () => nativeWidget.Hide (); + + public void Dispose () => nativeWidget.Dispose (); + + public void SetToolbarProvider (object toolbarProvider) + { + nativeWidget.SetToolbarProvider (toolbarProvider); + } + + public void OnPadContentShown () + { + //nativeWidget.SetToolbarProvider (toolbarProvider); + } + } + public class PropertyPad : PadContent, ICommandDelegator, IPropertyPad { public event EventHandler PropertyGridChanged; readonly bool isNative; - readonly IPropertyGrid propertyGrid; -#if MAC - MacPropertyGrid nativeGrid; - Gtk.Widget gtkWidget; -#endif - pg.PropertyGrid grid; InvisibleFrame frame; bool customWidget; @@ -64,31 +153,21 @@ public class PropertyPad : PadContent, ICommandDelegator, IPropertyPad internal object CommandRouteOrigin { get; set; } + readonly PropertyGridWrapper propertyGridWrapper; public PropertyPad () { frame = new InvisibleFrame (); #if MAC - isNative = true; - - if (isNative) { - - nativeGrid = new MacPropertyGrid (); - propertyGrid = nativeGrid; - nativeGrid.PropertyGridChanged += Grid_Changed; - gtkWidget = new GtkNSViewHost (nativeGrid); - - frame.Add (gtkWidget); - } else { -#endif - grid = new pg.PropertyGrid (); - propertyGrid = grid; - grid.Changed += Grid_Changed; - frame.Add (grid); -#if MAC - } + var widget = new PropertyMacHostWidget (); +#else + var widget = new pg.PropertyGrid (); #endif + propertyGridWrapper = new PropertyGridWrapper (widget); + frame.Add (propertyGridWrapper.Widget); + propertyGridWrapper.PropertyGridChanged += Grid_Changed; + frame.ShowAll (); } @@ -102,7 +181,7 @@ protected override void Initialize (IPadWindow container) base.Initialize (container); toolbarProvider.Attach (container.GetToolbar (DockPositionType.Top)); - propertyGrid.SetToolbarProvider (toolbarProvider); + propertyGridWrapper.SetToolbarProvider (toolbarProvider); #if MAC //native cocoa needs content shown to initialize stuff @@ -132,14 +211,14 @@ public override void Dispose() if (isNative) { container.PadContentShown -= Window_PadContentShown; container.PadContentHidden -= Window_PadContentHidden; - nativeGrid.PropertyGridChanged -= Grid_Changed; + propertyGridWrapper.PropertyGridChanged -= Grid_Changed; } else { #endif - grid.Changed -= Grid_Changed; + propertyGridWrapper.PropertyGridChanged -= Grid_Changed; #if MAC } #endif - propertyGrid.Dispose (); + propertyGridWrapper.Dispose (); DesignerSupport.Service.SetPad (null); base.Dispose (); } @@ -164,7 +243,7 @@ object ICommandDelegator.GetDelegatedCommandTarget () public bool IsGridEditing { get { AttachToolbarIfCustomWidget (); - return propertyGrid.IsEditing; + return propertyGridWrapper.IsGridEditing; } } @@ -173,7 +252,7 @@ public bool IsGridEditing { internal pg.PropertyGrid PropertyGrid { get { AttachToolbarIfCustomWidget (); - return isNative ? pGrid : grid; + return isNative ? pGrid : (pg.PropertyGrid) propertyGridWrapper.Widget; } } @@ -182,14 +261,14 @@ public void BlankPad () if (isNative) { AttachToolbarIfCustomWidget (); } - propertyGrid.BlankPad (); + propertyGridWrapper.BlankPad (); CommandRouteOrigin = null; } #if MAC void Window_PadContentShown (object sender, EventArgs e) { - propertyGrid.OnPadContentShown (); + propertyGridWrapper.OnPadContentShown (); if (customWidget && frame.Child is GtkNSViewHost viewHost) { viewHost.Visible = true; @@ -212,10 +291,10 @@ void AttachToolbarIfCustomWidget () #if MAC if (isNative) { - frame.Add (gtkWidget); + frame.Add (propertyGridWrapper.Widget); } else { #endif - frame.Add (grid); + frame.Add (propertyGridWrapper.Widget); #if MAC } #endif @@ -248,12 +327,12 @@ void ClearToolbar () public void SetCurrentObject (object lastComponent, object [] propertyProviders) { AttachToolbarIfCustomWidget (); - propertyGrid.SetCurrentObject (lastComponent, propertyProviders); + propertyGridWrapper.SetCurrentObject (lastComponent, propertyProviders); } public void PopulateGrid (bool saveEditSession) { - propertyGrid.Populate (saveEditSession); + propertyGridWrapper.PopulateGrid (saveEditSession); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs index 802c392dbc5..7aa546a43cf 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/IPropertyGrid.cs @@ -45,5 +45,7 @@ public interface IPropertyGrid : IDisposable void BlankPad (); void OnPadContentShown (); void Populate (bool saveEditSession); + + public Gtk.Widget Widget { get; } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs index 9d2330cbe2f..1077197a218 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs @@ -75,7 +75,9 @@ public class PropertyGrid: Gtk.VBox, IPropertyGrid PropertySort propertySort = PropertySort.Categorized; const string PROP_HELP_KEY = "MonoDevelop.PropertyPad.ShowHelp"; - + + public Widget Widget => this; + public PropertyGrid (): this (new EditorManager ()) { } From 2055191d27bda2df65253b65d5795a5df24ca8fd Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Tue, 8 Oct 2019 19:04:13 +0200 Subject: [PATCH 02/30] IPropertyPad based in IDisposable --- .../MonoDevelop.DesignerSupport/IPropertyPad.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs index 18c610f9465..445e893ed94 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/IPropertyPad.cs @@ -3,7 +3,7 @@ namespace MonoDevelop.DesignerSupport { - public interface IPropertyPad + public interface IPropertyPad : IDisposable { bool IsGridEditing { get; } From 5dfc17ca7dfb7fa1f9cbe80dc56067dbbddf171e Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Tue, 8 Oct 2019 20:29:39 +0200 Subject: [PATCH 03/30] Sends the target instead the Object Editor --- .../NativePropertyEditor/ComponentModelObjectEditor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs index 501d7d13975..82635e9dc3a 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs @@ -98,7 +98,7 @@ public Task> GetValueAsync (IPropertyInfo property, PropertyVari return Task.FromException> (new ArgumentException ($"Property should be a {nameof (DescriptorPropertyInfo)}", nameof (property))); } - T value = propertyInfo.GetValue (this); + T value = propertyInfo.GetValue (this.Target); var valueInfo = new ValueInfo { Value = value, Source = ValueSource.Local, @@ -121,7 +121,7 @@ public Task SetValueAsync (IPropertyInfo propertyInfo, ValueInfo value, Pr return Task.FromException (new ArgumentNullException (nameof (propertyInfo))); if (propertyInfo is DescriptorPropertyInfo info && info.CanWrite) { - info.SetValue (this, value.Value); + info.SetValue (this.Target, value.Value); RaisePropertyChanged (info); } else { return Task.FromException (new ArgumentException ($"Property should be a writeable {nameof (DescriptorPropertyInfo)}.", nameof (propertyInfo))); From 51da7ed25ceb0f7da09689f26de7ac8c0127232b Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Tue, 8 Oct 2019 21:22:44 +0200 Subject: [PATCH 04/30] Includes more properties to configure in the abstraction --- .../MacPropertyGrid.cs | 4 ++ .../PropertyPad.cs | 54 ++++++++++++------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index fc2f88a50d1..0b9a5ec5668 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -83,6 +83,10 @@ public void BlankPad () editorProvider.Clear (); } + public object CurrentObject { + get => currentSelectedObject.Target; + } + public void SetCurrentObject (object lastComponent, object [] propertyProviders) { if (lastComponent != null) { diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs index 88c39408b8e..b3e01ff238e 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs @@ -41,7 +41,6 @@ using MonoDevelop.Components; using System; using Gtk; -using MonoDevelop.Core.FeatureConfiguration; namespace MonoDevelop.DesignerSupport { @@ -56,6 +55,13 @@ class PropertyMacHostWidget : IPropertyGrid public Widget Widget => host; + public object CurrentObject { + get => view.CurrentObject; + set { + view.SetCurrentObject (value, new object [] { value }); + } + } + public PropertyMacHostWidget () { view = new MacPropertyGrid (); @@ -92,6 +98,8 @@ public void SetToolbarProvider (object toolbarProvider) public interface IPropertyGrid : IPropertyPad { + object CurrentObject { get; set; } + void Hide (); void Show (); @@ -100,7 +108,7 @@ public interface IPropertyGrid : IPropertyPad Gtk.Widget Widget { get; } } - class PropertyGridWrapper : IPropertyGrid + public class PropertyGridWrapper : IPropertyGrid { public bool IsGridEditing => nativeWidget.IsGridEditing; @@ -108,11 +116,26 @@ class PropertyGridWrapper : IPropertyGrid public Gtk.Widget Widget => nativeWidget.Widget; + public bool ShowToolbar { get; set; } + public ShadowType ShadowType { get; set; } + public bool ShowHelp { get; set; } + + public object CurrentObject { + get => nativeWidget.CurrentObject; + set => nativeWidget.CurrentObject = value; + } + + public bool Sensitive { get; set; } + IPropertyGrid nativeWidget; - public PropertyGridWrapper (IPropertyGrid splitterWidget) + public PropertyGridWrapper () { - nativeWidget = splitterWidget; +#if MAC + nativeWidget = new PropertyMacHostWidget (); +#else + nativeWidget = new pg.PropertyGrid (); +#endif } public void BlankPad () @@ -138,6 +161,11 @@ public void OnPadContentShown () { //nativeWidget.SetToolbarProvider (toolbarProvider); } + + public void CommitPendingChanges () + { + //to implement + } } public class PropertyPad : PadContent, ICommandDelegator, IPropertyPad @@ -159,22 +187,15 @@ public PropertyPad () { frame = new InvisibleFrame (); -#if MAC - var widget = new PropertyMacHostWidget (); -#else - var widget = new pg.PropertyGrid (); -#endif - propertyGridWrapper = new PropertyGridWrapper (widget); + propertyGridWrapper = new PropertyGridWrapper (); frame.Add (propertyGridWrapper.Widget); propertyGridWrapper.PropertyGridChanged += Grid_Changed; frame.ShowAll (); } - void Grid_Changed (object sender, EventArgs e) - { + void Grid_Changed (object sender, EventArgs e) => PropertyGridChanged?.Invoke (this, e); - } protected override void Initialize (IPadWindow container) { @@ -211,13 +232,10 @@ public override void Dispose() if (isNative) { container.PadContentShown -= Window_PadContentShown; container.PadContentHidden -= Window_PadContentHidden; - propertyGridWrapper.PropertyGridChanged -= Grid_Changed; - } else { -#endif - propertyGridWrapper.PropertyGridChanged -= Grid_Changed; -#if MAC } #endif + + propertyGridWrapper.PropertyGridChanged -= Grid_Changed; propertyGridWrapper.Dispose (); DesignerSupport.Service.SetPad (null); base.Dispose (); From c029d80e3e2b16e890817a0618cb524c1920ecc6 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Tue, 8 Oct 2019 21:23:40 +0200 Subject: [PATCH 05/30] Changes XmlFormattingPolicyPanelWidget to use wrapper instead gtk widget --- .../addins/Xml/Formatting/XmlFormattingPolicyPanelWidget.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/src/addins/Xml/Formatting/XmlFormattingPolicyPanelWidget.cs b/main/src/addins/Xml/Formatting/XmlFormattingPolicyPanelWidget.cs index 81cc6c8fd8c..18fc9f6030a 100644 --- a/main/src/addins/Xml/Formatting/XmlFormattingPolicyPanelWidget.cs +++ b/main/src/addins/Xml/Formatting/XmlFormattingPolicyPanelWidget.cs @@ -59,7 +59,7 @@ public XmlFormattingPolicyPanelWidget () Button buttonRemove; Label labelScopes; Table tableScopes; - MonoDevelop.Components.PropertyGrid.PropertyGrid propertyGrid; + DesignerSupport.PropertyGridWrapper propertyGrid; Button buttonAdvanced; void Build () @@ -85,7 +85,7 @@ void Build () ColumnSpacing = 6 }; - propertyGrid = new MonoDevelop.Components.PropertyGrid.PropertyGrid { + propertyGrid = new DesignerSupport.PropertyGridWrapper { ShowToolbar = false, ShowHelp = false }; @@ -107,7 +107,7 @@ void Build () var rightVBox = new VBox (false, 6); rightVBox.PackStart (labelScopes, false, false, 0); rightVBox.PackStart (tableScopes, false, false, 0); - rightVBox.PackStart (propertyGrid, true, true, 0); + rightVBox.PackStart (propertyGrid.Widget, true, true, 0); var mainBox = new HBox (false, 6); mainBox.PackStart (boxScopes, false, false, 0); From cc262707259b7b01cad07af5b4080a6cf5a00b21 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Tue, 15 Oct 2019 20:05:04 +0200 Subject: [PATCH 06/30] PropertyGridChanged is now correctly propagated in abstraction --- .../PropertyPad.cs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs index b3e01ff238e..e0a8ecc7f4b 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs @@ -47,7 +47,7 @@ namespace MonoDevelop.DesignerSupport class PropertyMacHostWidget : IPropertyGrid { readonly GtkNSViewHost host; - readonly MacPropertyGrid view; + MacPropertyGrid view; public bool IsGridEditing => view.IsEditing; @@ -66,8 +66,12 @@ public PropertyMacHostWidget () { view = new MacPropertyGrid (); host = new GtkNSViewHost (view); + + view.PropertyGridChanged += View_PropertyGridChanged; } + private void View_PropertyGridChanged (object sender, EventArgs e) => PropertyGridChanged?.Invoke (this, e); + public void SetCurrentObject (object obj, object [] propertyProviders) => view.SetCurrentObject (obj, propertyProviders); @@ -75,7 +79,13 @@ public void BlankPad () => view.BlankPad (); public void Dispose () - => view.Dispose (); + { + if (view != null) { + view.PropertyGridChanged -= View_PropertyGridChanged; + view.Dispose (); + view = null; + } + } public void Hide () => view.Hidden = true; public void Show () => view.Hidden = false; @@ -94,6 +104,11 @@ public void SetToolbarProvider (object toolbarProvider) { //not implemented; } + + public void CommitPendingChanges () + { + //not implemented; + } } public interface IPropertyGrid : IPropertyPad @@ -105,6 +120,8 @@ public interface IPropertyGrid : IPropertyPad void SetToolbarProvider (object toolbarProvider); + void CommitPendingChanges (); + Gtk.Widget Widget { get; } } @@ -136,8 +153,12 @@ public PropertyGridWrapper () #else nativeWidget = new pg.PropertyGrid (); #endif + nativeWidget.PropertyGridChanged += NativeWidget_PropertyGridChanged; } + private void NativeWidget_PropertyGridChanged (object sender, EventArgs e) + => PropertyGridChanged?.Invoke (this, e); + public void BlankPad () => nativeWidget.BlankPad (); @@ -150,7 +171,14 @@ public void SetCurrentObject (object lastComponent, object [] propertyProviders) public void Show () => nativeWidget.Show (); public void Hide () => nativeWidget.Hide (); - public void Dispose () => nativeWidget.Dispose (); + public void Dispose () + { + if (nativeWidget != null) { + nativeWidget.PropertyGridChanged += NativeWidget_PropertyGridChanged; + nativeWidget.Dispose (); + nativeWidget = null; + } + } public void SetToolbarProvider (object toolbarProvider) { @@ -164,6 +192,7 @@ public void OnPadContentShown () public void CommitPendingChanges () { + nativeWidget.CommitPendingChanges (); //to implement } } From 119513a0614cebe54b9ba8bb37e640fab0a2c0b9 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 16 Oct 2019 04:35:16 +0200 Subject: [PATCH 07/30] Impoves current logic and adds some logic to handle better nullable editors --- .../PropertyInfo/DescriptorPropertyInfo.cs | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/PropertyInfo/DescriptorPropertyInfo.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/PropertyInfo/DescriptorPropertyInfo.cs index be7ead2146c..5a524f4243d 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/PropertyInfo/DescriptorPropertyInfo.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/PropertyInfo/DescriptorPropertyInfo.cs @@ -145,18 +145,33 @@ public static ITypeInfo ToTypeInfo (Type type, bool isRelevant = true) internal virtual T GetValue (object target) { - T converted = default; + var converted = default (T); object value = null; bool canConvert = false; + try { + value = PropertyDescriptor.GetValue (PropertyProvider); + var currentType = typeof (T); + var underlyingType = Nullable.GetUnderlyingType (currentType); + + //proppy has some editors based in nullable types + if (underlyingType != null) { + var converterNullable = new NullableConverter (currentType); + if (converterNullable.CanConvertFrom (underlyingType)) { + object notNullableValue = Convert.ChangeType (value, underlyingType); + return (T)converterNullable.ConvertFrom (notNullableValue); + } + } + var tc = PropertyDescriptor.Converter; - canConvert = tc.CanConvertTo (typeof (T)); + canConvert = tc.CanConvertTo (currentType); if (canConvert) { - converted = (T)tc.ConvertTo (value, typeof (T)); + converted = (T)tc.ConvertTo (value, currentType); } else { - converted = (T)value; + converted = (T)Convert.ChangeType (value, currentType); } + } catch (Exception ex) { LogInternalError ($"Error trying to get and convert value:'{value}' canconvert: {canConvert} T:{typeof (T).FullName} ", ex); } @@ -167,21 +182,22 @@ internal virtual void SetValue (object target, T value) { try { - var currentType = typeof (T) ; + var currentType = typeof (T); //TODO: Proppy in Boolean types uses bool? to handle it, but this will fail using converters //thats because we need ensure take the underlying type currentType = Nullable.GetUnderlyingType (currentType) ?? currentType; - object notNulleableValue = Convert.ChangeType (value, currentType); + object notNullableValue; var tc = PropertyDescriptor.Converter; if (tc.CanConvertFrom (currentType)) { - var result = tc.ConvertFrom (notNulleableValue); - PropertyDescriptor.SetValue (PropertyProvider, result); + notNullableValue = tc.ConvertFrom (value); } else { - notNulleableValue = Convert.ChangeType (value, this.Type); - PropertyDescriptor.SetValue (PropertyProvider, notNulleableValue); + notNullableValue = Convert.ChangeType (value, currentType); } + + PropertyDescriptor.SetValue (PropertyProvider, notNullableValue); + } catch (Exception ex) { LogInternalError ($"Error trying to set and convert a value: {value} T:{typeof (T).FullName}", ex); } From eb2a0cc9b156f8fa41a27c30787acbac941ce05a Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 16 Oct 2019 04:57:38 +0200 Subject: [PATCH 08/30] Uses default value sources --- .../NativePropertyEditor/ComponentModelEditorProvider.cs | 2 +- .../NativePropertyEditor/ComponentModelObjectEditor.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelEditorProvider.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelEditorProvider.cs index 2d9ebdac6ee..5a95a0b4bb0 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelEditorProvider.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelEditorProvider.cs @@ -116,7 +116,7 @@ protected static DescriptorPropertyInfo CreatePropertyInfo (System.ComponentMode { var typeDescriptorContext = new TypeDescriptorContext (propertyProvider, propertyDescriptor); - var valueSources = ValueSources.Local | ValueSources.Default; + var valueSources = ValueSources.Default; if (propertyDescriptor.PropertyType.IsEnum) { if (propertyDescriptor.PropertyType.IsDefined (typeof (FlagsAttribute), inherit: false)) return new FlagDescriptorPropertyInfo (typeDescriptorContext, valueSources); diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs index 82635e9dc3a..2c7675ceb5c 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs @@ -101,7 +101,7 @@ public Task> GetValueAsync (IPropertyInfo property, PropertyVari T value = propertyInfo.GetValue (this.Target); var valueInfo = new ValueInfo { Value = value, - Source = ValueSource.Local, + Source = ValueSource.Default, }; return Task.FromResult (valueInfo); } From 2f4ee83f47bbd05e2f0b38bf3153ac770379dd96 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 16 Oct 2019 06:00:47 +0200 Subject: [PATCH 09/30] Changes current PropertyPad to use PropertyGridWrapper in Preferences Formatting F# panel --- .../FSharpFormattingPanelWidget.fs | 10 +++++----- .../MonoDevelop.DesignerSupport/PropertyPad.cs | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpFormattingPanelWidget.fs b/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpFormattingPanelWidget.fs index a5487f4f213..48cb88f58e2 100644 --- a/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpFormattingPanelWidget.fs +++ b/main/external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpFormattingPanelWidget.fs @@ -2,7 +2,7 @@ open Gtk open MonoDevelop.Core -open MonoDevelop.Components.PropertyGrid +open MonoDevelop.DesignerSupport // Handwritten GUI, feel free to edit @@ -21,7 +21,7 @@ type FSharpFormattingPolicyPanelWidget() = let mutable hbox2 : Gtk.HBox = null let mutable vbox4 : Gtk.VBox = null let mutable tableScopes : Gtk.Table = null - let mutable propertyGrid : PropertyGrid = null + let mutable propertyGrid : PropertyGridWrapper = null let getName format = if format = policy.DefaultFormat then @@ -125,12 +125,12 @@ type FSharpFormattingPolicyPanelWidget() = w8.Expand <- false w8.Fill <- false // Container child vbox4.Gtk.Box+BoxChild - propertyGrid <- new PropertyGrid() + propertyGrid <- new PropertyGridWrapper () propertyGrid.Name <- "propertyGrid" propertyGrid.ShowToolbar <- false propertyGrid.ShowHelp <- false - vbox4.Add (propertyGrid) - let w9 = vbox4.[propertyGrid] :?> Gtk.Box.BoxChild + vbox4.Add (propertyGrid.Widget) + let w9 = vbox4.[propertyGrid.Widget] :?> Gtk.Box.BoxChild w9.Position <- 2 hbox1.Add(vbox4) let w10 = hbox1.[vbox4] :?> Gtk.Box.BoxChild diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs index e0a8ecc7f4b..6f8ababd1cc 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs @@ -49,6 +49,8 @@ class PropertyMacHostWidget : IPropertyGrid readonly GtkNSViewHost host; MacPropertyGrid view; + public string Name { get; set; } + public bool IsGridEditing => view.IsEditing; public event EventHandler PropertyGridChanged; @@ -113,6 +115,8 @@ public void CommitPendingChanges () public interface IPropertyGrid : IPropertyPad { + public string Name { get; set; } + object CurrentObject { get; set; } void Hide (); @@ -127,6 +131,11 @@ public interface IPropertyGrid : IPropertyPad public class PropertyGridWrapper : IPropertyGrid { + public string Name { + get => nativeWidget.Name; + set => nativeWidget.Name = value; + } + public bool IsGridEditing => nativeWidget.IsGridEditing; public event EventHandler PropertyGridChanged; From 8261834d707e69bf35b51917bf1ad32a9fc7f04b Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 16 Oct 2019 12:47:16 +0200 Subject: [PATCH 10/30] Adds IsEnabled hack to cover missing feature in proppy --- .../MonoDevelop.DesignerSupport/MacPropertyGrid.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 0b9a5ec5668..6a15840d1f9 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -49,6 +49,14 @@ class MacPropertyGrid : NSView public bool IsEditing => false; + //Small hack to cover the missing Proppy feature + public bool Sensitive { get; set; } + public override NSView HitTest (CGPoint aPoint) + { + if (!Sensitive) return null; + return base.HitTest (aPoint); + } + public event EventHandler PropertyGridChanged; public MacPropertyGrid () From a95249c81419291ced4bcf8673a242dad1fb57ee Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 16 Oct 2019 13:36:25 +0200 Subject: [PATCH 11/30] reordering property pad properties --- .../MacPropertyGrid.cs | 16 ++++ .../PropertyPad.cs | 93 ++++++++++++------- 2 files changed, 75 insertions(+), 34 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 6a15840d1f9..509d72738ec 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -95,6 +95,22 @@ public object CurrentObject { get => currentSelectedObject.Target; } + //HACK: this + bool showToolbar = true; + public bool ShowToolbar { + get => showToolbar; + set { + //we ensure remove current constraints from proppy + + + if (showToolbar) { + + } else { + //we only want include + } + } + } + public void SetCurrentObject (object lastComponent, object [] propertyProviders) { if (lastComponent != null) { diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs index 6f8ababd1cc..d0513c13e49 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs @@ -46,16 +46,29 @@ namespace MonoDevelop.DesignerSupport { class PropertyMacHostWidget : IPropertyGrid { + public event EventHandler PropertyGridChanged; + readonly GtkNSViewHost host; + MacPropertyGrid view; public string Name { get; set; } + public bool ShowHelp { get; set; } //not implemented + + public ShadowType ShadowType { get; set; } //not implemented + public Widget Widget => host; public bool IsGridEditing => view.IsEditing; - public event EventHandler PropertyGridChanged; + public bool ShowToolbar { + get => view.ShowToolbar; + set => view.ShowToolbar = value; + } - public Widget Widget => host; + public bool Sensitive { + get => view.Sensitive; + set => view.Sensitive = value; + } public object CurrentObject { get => view.CurrentObject; @@ -72,23 +85,13 @@ public PropertyMacHostWidget () view.PropertyGridChanged += View_PropertyGridChanged; } - private void View_PropertyGridChanged (object sender, EventArgs e) => PropertyGridChanged?.Invoke (this, e); + void View_PropertyGridChanged (object sender, EventArgs e) + => PropertyGridChanged?.Invoke (this, e); public void SetCurrentObject (object obj, object [] propertyProviders) => view.SetCurrentObject (obj, propertyProviders); - public void BlankPad () - => view.BlankPad (); - - public void Dispose () - { - if (view != null) { - view.PropertyGridChanged -= View_PropertyGridChanged; - view.Dispose (); - view = null; - } - } - + public void BlankPad () => view.BlankPad (); public void Hide () => view.Hidden = true; public void Show () => view.Hidden = false; @@ -111,22 +114,33 @@ public void CommitPendingChanges () { //not implemented; } + + public void Dispose () + { + if (view != null) { + view.PropertyGridChanged -= View_PropertyGridChanged; + view.Dispose (); + view = null; + } + } } public interface IPropertyGrid : IPropertyPad { - public string Name { get; set; } - + bool ShowToolbar { get; set; } + bool ShowHelp { get; set; } + bool Sensitive { get; set; } + string Name { get; set; } object CurrentObject { get; set; } + Gtk.Widget Widget { get; } + ShadowType ShadowType { get; set; } + void Hide (); void Show (); void SetToolbarProvider (object toolbarProvider); - void CommitPendingChanges (); - - Gtk.Widget Widget { get; } } public class PropertyGridWrapper : IPropertyGrid @@ -136,23 +150,37 @@ public string Name { set => nativeWidget.Name = value; } - public bool IsGridEditing => nativeWidget.IsGridEditing; - public event EventHandler PropertyGridChanged; public Gtk.Widget Widget => nativeWidget.Widget; - public bool ShowToolbar { get; set; } - public ShadowType ShadowType { get; set; } - public bool ShowHelp { get; set; } + public bool ShowToolbar { + get => nativeWidget.ShowToolbar; + set => nativeWidget.ShowToolbar = value; + } + + public ShadowType ShadowType { + get => nativeWidget.ShadowType; + set => nativeWidget.ShadowType = value; + } + + public bool ShowHelp { + get => nativeWidget.ShowHelp; + set => nativeWidget.ShowHelp = value; + } + + public bool Sensitive { + get => nativeWidget.Sensitive; + set => nativeWidget.Sensitive = value; + } + + public bool IsGridEditing => nativeWidget.IsGridEditing; public object CurrentObject { get => nativeWidget.CurrentObject; set => nativeWidget.CurrentObject = value; } - public bool Sensitive { get; set; } - IPropertyGrid nativeWidget; public PropertyGridWrapper () @@ -171,8 +199,8 @@ private void NativeWidget_PropertyGridChanged (object sender, EventArgs e) public void BlankPad () => nativeWidget.BlankPad (); - public void PopulateGrid (bool saveEditSession) => - nativeWidget.PopulateGrid (saveEditSession); + public void PopulateGrid (bool saveEditSession) + => nativeWidget.PopulateGrid (saveEditSession); public void SetCurrentObject (object lastComponent, object [] propertyProviders) => nativeWidget.SetCurrentObject (lastComponent, propertyProviders); @@ -196,14 +224,11 @@ public void SetToolbarProvider (object toolbarProvider) public void OnPadContentShown () { - //nativeWidget.SetToolbarProvider (toolbarProvider); + //not implemented } - public void CommitPendingChanges () - { + public void CommitPendingChanges () => nativeWidget.CommitPendingChanges (); - //to implement - } } public class PropertyPad : PadContent, ICommandDelegator, IPropertyPad From 01f38cddbc55314fafbb003f5fc85d24b7bd906c Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 16 Oct 2019 17:01:25 +0200 Subject: [PATCH 12/30] Adds API to hide/show toolbar in proppy --- .../MacPropertyGrid.cs | 51 ++++++++++++++++--- .../PropertyPad.cs | 4 +- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 509d72738ec..1d886827c85 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -36,6 +36,7 @@ using Xamarin.PropertyEditing.Mac; using AppKit; using CoreGraphics; +using System.Linq; namespace MonoDevelop.DesignerSupport { @@ -66,6 +67,17 @@ public MacPropertyGrid () }; AddSubview (propertyEditorPanel); + #region Header Proppy Hack + + header = propertyEditorPanel.Subviews [0]; + propertyList = propertyEditorPanel.Subviews [1]; + + //we need the second item constrained with the property list + var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); + border = topConstraint.SecondItem as NSView; + + #endregion + editorProvider = new ComponentModelEditorProvider (); editorProvider.PropertyChanged += EditorProvider_PropertyChanged; @@ -95,22 +107,45 @@ public object CurrentObject { get => currentSelectedObject.Target; } - //HACK: this - bool showToolbar = true; - public bool ShowToolbar { - get => showToolbar; - set { - //we ensure remove current constraints from proppy + #region Header Proppy Hack + + NSView header; + NSView propertyList; + NSView border; + + void ShowHeader () + { + var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); + propertyEditorPanel.RemoveConstraint (topConstraint); + propertyEditorPanel.AddConstraint (NSLayoutConstraint.Create (this.propertyList, NSLayoutAttribute.Top, NSLayoutRelation.Equal, border, NSLayoutAttribute.Bottom, 1, 0)); + header.Hidden = false; + } - if (showToolbar) { + void HideHeader () + { + header.Hidden = true; + + var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); + propertyEditorPanel.RemoveConstraint (topConstraint); + propertyEditorPanel.AddConstraint (NSLayoutConstraint.Create (this.propertyList, NSLayoutAttribute.Top, NSLayoutRelation.Equal, propertyEditorPanel, NSLayoutAttribute.Top, 1, 0)); + } + //HACK: this + public bool ToolbarVisible { + get => !header.Hidden; + set { + //we ensure remove current constraints from proppy + if (value) { + ShowHeader (); } else { - //we only want include + HideHeader (); } } } + #endregion + public void SetCurrentObject (object lastComponent, object [] propertyProviders) { if (lastComponent != null) { diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs index d0513c13e49..50b396aa633 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs @@ -61,8 +61,8 @@ class PropertyMacHostWidget : IPropertyGrid public bool IsGridEditing => view.IsEditing; public bool ShowToolbar { - get => view.ShowToolbar; - set => view.ShowToolbar = value; + get => view.ToolbarVisible; + set => view.ToolbarVisible = value; } public bool Sensitive { From 447fa526aa37aae933fee5baf6e220e30a14342a Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 17 Oct 2019 10:25:37 +0200 Subject: [PATCH 13/30] Sets Sensitive to true as value as default --- .../MonoDevelop.DesignerSupport/MacPropertyGrid.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 1d886827c85..b78b1cae894 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -51,7 +51,7 @@ class MacPropertyGrid : NSView public bool IsEditing => false; //Small hack to cover the missing Proppy feature - public bool Sensitive { get; set; } + public bool Sensitive { get; set; } = true; public override NSView HitTest (CGPoint aPoint) { if (!Sensitive) return null; From 534270faa950a87ae80c5978c5ce70ccc5d45f5e Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 17 Oct 2019 10:26:11 +0200 Subject: [PATCH 14/30] Removes not used INameableObject --- .../ComponentModelObjectEditor.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs index 2c7675ceb5c..68adeb695e5 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs @@ -35,12 +35,11 @@ namespace MonoDevelop.DesignerSupport { class ComponentModelObjectEditor - : IObjectEditor, INameableObject, IDisposable + : IObjectEditor, IDisposable { internal const string ComboSeparatorString = "--"; private readonly ComponentModelTarget propertyItem; - public string Name { get; private set; } static IReadOnlyList defaultHandlerList = new List ().AsReadOnly (); static AssignableTypesResult defaultAssignableTypeResult = new AssignableTypesResult (new List ().AsReadOnly ()); @@ -84,7 +83,7 @@ public Task GetAssignableTypesAsync (IPropertyInfo proper public Task> GetHandlersAsync (IEventInfo ev) => Task.FromResult(defaultHandlerList); - public Task GetNameAsync () => Task.FromResult (Name); + public Task GetNameAsync () => Task.FromResult ((string) null); public Task> GetPropertyVariantsAsync (IPropertyInfo property) => Task.FromResult> (Array.Empty ()); @@ -108,12 +107,6 @@ public Task> GetValueAsync (IPropertyInfo property, PropertyVari public Task RemovePropertyVariantAsync (IPropertyInfo property, PropertyVariation variant) => Task.CompletedTask; - public Task SetNameAsync (string name) - { - Name = name; - return Task.CompletedTask; - } - public Task SetValueAsync (IPropertyInfo propertyInfo, ValueInfo value, PropertyVariation variations = null) { try { From 63e38055f0c198b9affa65c9c6bafc04f02ee617 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 17 Oct 2019 11:03:30 +0200 Subject: [PATCH 15/30] Fixes background color in cases of header not visible --- .../MonoDevelop.DesignerSupport/MacPropertyGrid.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index b78b1cae894..ac3fd3b39c9 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -43,6 +43,8 @@ namespace MonoDevelop.DesignerSupport class MacPropertyGrid : NSView { readonly MacPropertyEditorPanel propertyEditorPanel; + readonly MonoDevelopHostResourceProvider hostResourceProvider; + ComponentModelEditorProvider editorProvider; ComponentModelTarget currentSelectedObject; @@ -50,7 +52,7 @@ class MacPropertyGrid : NSView public bool IsEditing => false; - //Small hack to cover the missing Proppy feature + //Small hack to cover the missing Proppy feature to enable/disable the control public bool Sensitive { get; set; } = true; public override NSView HitTest (CGPoint aPoint) { @@ -62,7 +64,9 @@ public override NSView HitTest (CGPoint aPoint) public MacPropertyGrid () { - propertyEditorPanel = new MacPropertyEditorPanel (new MonoDevelopHostResourceProvider ()) { + hostResourceProvider = new MonoDevelopHostResourceProvider (); + + propertyEditorPanel = new MacPropertyEditorPanel (hostResourceProvider) { ShowHeader = false }; AddSubview (propertyEditorPanel); @@ -71,6 +75,8 @@ public MacPropertyGrid () header = propertyEditorPanel.Subviews [0]; propertyList = propertyEditorPanel.Subviews [1]; + internalTableView = propertyList.Subviews.OfType () + .FirstOrDefault ().DocumentView as NSTableView; //we need the second item constrained with the property list var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); @@ -111,10 +117,13 @@ public object CurrentObject { NSView header; NSView propertyList; + NSTableView internalTableView; NSView border; void ShowHeader () { + internalTableView.BackgroundColor = hostResourceProvider.GetNamedColor (NamedResources.PadBackgroundColor); + var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); propertyEditorPanel.RemoveConstraint (topConstraint); propertyEditorPanel.AddConstraint (NSLayoutConstraint.Create (this.propertyList, NSLayoutAttribute.Top, NSLayoutRelation.Equal, border, NSLayoutAttribute.Bottom, 1, 0)); @@ -124,6 +133,7 @@ void ShowHeader () void HideHeader () { + internalTableView.BackgroundColor = NSColor.Clear; header.Hidden = true; var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); From 051bdc3eb776b6a595290961dbcf0767900fc45e Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 17 Oct 2019 14:48:23 +0200 Subject: [PATCH 16/30] Merges Show/Hide methods into a single one --- .../MacPropertyGrid.cs | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index ac3fd3b39c9..642d95be1cb 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -120,25 +120,20 @@ public object CurrentObject { NSTableView internalTableView; NSView border; - void ShowHeader () + void ShowToolbar (bool enabled) { - internalTableView.BackgroundColor = hostResourceProvider.GetNamedColor (NamedResources.PadBackgroundColor); - var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); propertyEditorPanel.RemoveConstraint (topConstraint); - propertyEditorPanel.AddConstraint (NSLayoutConstraint.Create (this.propertyList, NSLayoutAttribute.Top, NSLayoutRelation.Equal, border, NSLayoutAttribute.Bottom, 1, 0)); - - header.Hidden = false; - } - - void HideHeader () - { - internalTableView.BackgroundColor = NSColor.Clear; - header.Hidden = true; - var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); - propertyEditorPanel.RemoveConstraint (topConstraint); - propertyEditorPanel.AddConstraint (NSLayoutConstraint.Create (this.propertyList, NSLayoutAttribute.Top, NSLayoutRelation.Equal, propertyEditorPanel, NSLayoutAttribute.Top, 1, 0)); + if (enabled) { + internalTableView.BackgroundColor = hostResourceProvider.GetNamedColor (NamedResources.PadBackgroundColor); + header.Hidden = false; + propertyEditorPanel.AddConstraint (NSLayoutConstraint.Create (this.propertyList, NSLayoutAttribute.Top, NSLayoutRelation.Equal, border, NSLayoutAttribute.Bottom, 1, 0)); + } else { + internalTableView.BackgroundColor = NSColor.Clear; + header.Hidden = true; + propertyEditorPanel.AddConstraint (NSLayoutConstraint.Create (this.propertyList, NSLayoutAttribute.Top, NSLayoutRelation.Equal, propertyEditorPanel, NSLayoutAttribute.Top, 1, 0)); + } } //HACK: this @@ -146,11 +141,7 @@ public bool ToolbarVisible { get => !header.Hidden; set { //we ensure remove current constraints from proppy - if (value) { - ShowHeader (); - } else { - HideHeader (); - } + ShowToolbar (value); } } From 341366ffc2186811e782d33f35807e27b7e3f16b Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 23 Oct 2019 03:29:10 +0200 Subject: [PATCH 17/30] Registers as top window in MessageService every CustomRunDialog opened --- main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs index 7a048654c08..5c95d9d7285 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs @@ -394,6 +394,7 @@ public static int RunCustomDialog (Dialog dlg, Window parent) try { Xwt.MessageDialog.RootWindow = Xwt.Toolkit.CurrentEngine.WrapWindow (dialog); IdeApp.DisableIdleActions (); + IdeApp.CommandService.RegisterTopWindow (dialog); int result = GtkWorkarounds.RunDialogWithNotification (dialog); // Focus parent window once the dialog is ran, as focus gets lost if (parent != null) { From 93d42e91d85eebbf51a2207c45107978677931e0 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 23 Oct 2019 13:02:05 +0200 Subject: [PATCH 18/30] Fixes current keydown hack to calculate nextkeyview --- .../CommandManager.cs | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 4dbc6ad46bb..2668eebd56f 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -507,16 +507,43 @@ internal bool ProcessKeyEvent (Gdk.EventKey ev) if (currentEvent != null && currentEvent.Type == AppKit.NSEventType.KeyDown && - firstResponder != null && - firstResponder != window.ContentView) { - firstResponder.KeyDown (currentEvent); + firstResponder is AppKit.NSView view && + view != window.ContentView) { + + if (currentEvent.KeyCode == (ushort)AppKit.NSKey.Tab) { + view = FindValidKeyView (view); + AppKit.NSView next = null; + if (currentEvent.ModifierFlags.HasFlag (AppKit.NSEventModifierMask.ShiftKeyMask)) { + next = view.PreviousValidKeyView; + } else { + next = view.NextValidKeyView; + } + window.MakeFirstResponder (next); + } else { + view.KeyDown (currentEvent); + } return true; } #endif - return false; } + + static AppKit.NSView FindValidKeyView (AppKit.NSView view) + { + if (view == null) + return null; + + if (view.AcceptsFirstResponder ()) { + if (view.Superview?.Superview is AppKit.NSControl control && control.CurrentEditor == view) { + return FindValidKeyView (control); + } + return view; + } + + return FindValidKeyView (view.Superview); + } + bool ProcessKeyEventCore (Gdk.EventKey ev) { if (!IsEnabled) From 18307d45aa9b25bbab629fc450e0131457d38635 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 23 Oct 2019 14:07:40 +0200 Subject: [PATCH 19/30] Removes current internal keyloop hack in Toolbox to use new NextKeyView based system --- .../MacToolbox.cs | 83 ++++--------------- .../NativeViews/SearchTextField.cs | 26 +----- .../NativeViews/ToggleButton.cs | 7 -- .../Mac/NativeViewHelper.cs | 17 +++- 4 files changed, 32 insertions(+), 101 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs index 2c942b6275a..3f38ecf1c68 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs @@ -76,18 +76,13 @@ NSView GetNextFocusableViewForView (NSView view, int nextPositionInArray = 1) public void AddViews (params NSView [] views) => viewsKeyLoopOrder.AddRange (views); - public void FocusNextView (NSView view, int nextPositionInArray = 1) + public void RecalculeNextResponderChain () { - var window = view?.Window; - if (window == null) { - return; - } - var nextView = GetNextFocusableViewForView (view, nextPositionInArray); - if (nextView != null) { - window.MakeFirstResponder (nextView); - } else { - //in case of no view found we follow the next logical view - window.MakeFirstResponder (nextPositionInArray >= 0 ? view.NextKeyView : view.PreviousKeyView); + NSView currentView = viewsKeyLoopOrder.FirstOrDefault (); + while (currentView != null) { + var nextView = GetNextFocusableViewForView (currentView, 1); + currentView.NextKeyView = nextView; + currentView = nextView; } } } @@ -125,15 +120,15 @@ class MacToolbox : NSView, IPropertyPadProvider, IToolboxConfiguration NSTextField messageTextField; - KeyViewLoopDelegate keyViewLoopDelegate; - + readonly KeyViewLoopDelegate keyViewLoopDelegate; + public MacToolbox (ToolboxService toolboxService, IPadWindow container) { WantsLayer = true; keyViewLoopDelegate = new KeyViewLoopDelegate (); - - verticalStackView = new NSStackView () { + + verticalStackView = new UnfocusableStackView () { Orientation = NSUserInterfaceLayoutOrientation.Vertical, Alignment = NSLayoutAttribute.Leading, Spacing = 0, @@ -165,7 +160,6 @@ public MacToolbox (ToolboxService toolboxService, IPadWindow container) filterEntry.AccessibilityTitle = GettextCatalog.GetString ("Search Toolbox"); filterEntry.AccessibilityHelp = GettextCatalog.GetString ("Enter a term to search for it in the toolbox"); filterEntry.Activated += FilterTextChanged; - filterEntry.CommandRaised += FilterEntry_CommandRaised; horizontalStackView.AddArrangedSubview (filterEntry); @@ -178,8 +172,7 @@ public MacToolbox (ToolboxService toolboxService, IPadWindow container) catToggleButton.ToolTip = GettextCatalog.GetString ("Show categories"); catToggleButton.AccessibilityHelp = GettextCatalog.GetString ("Toggle to show categories"); catToggleButton.Activated += ToggleCategorisation; - catToggleButton.KeyDownPressed += OnKeyDownKeyLoop; - + horizontalStackView.AddArrangedSubview (catToggleButton); catToggleButton.SetContentCompressionResistancePriority ((int)NSLayoutPriority.DefaultHigh, NSLayoutConstraintOrientation.Horizontal); @@ -191,8 +184,6 @@ public MacToolbox (ToolboxService toolboxService, IPadWindow container) compactModeToggleButton.AccessibilityTitle = GettextCatalog.GetString ("Compact Layout"); compactModeToggleButton.AccessibilityHelp = GettextCatalog.GetString ("Toggle for toolbox to use compact layout"); compactModeToggleButton.Activated += ToggleCompactMode; - compactModeToggleButton.KeyDownPressed += OnKeyDownKeyLoop; - horizontalStackView.AddArrangedSubview (compactModeToggleButton); @@ -205,7 +196,6 @@ public MacToolbox (ToolboxService toolboxService, IPadWindow container) toolboxAddButton.AccessibilityHelp = GettextCatalog.GetString ("Add toolbox items"); toolboxAddButton.ToolTip = GettextCatalog.GetString ("Add toolbox items"); toolboxAddButton.Activated += ToolboxAddButton_Clicked; - toolboxAddButton.KeyDownPressed += OnKeyDownKeyLoop; horizontalStackView.AddArrangedSubview (toolboxAddButton); @@ -218,7 +208,7 @@ public MacToolbox (ToolboxService toolboxService, IPadWindow container) AccessibilityTitle = GettextCatalog.GetString ("Toolbox Toolbar"), }; - var scrollView = new NSScrollView () { + var scrollView = new UnfocusableScrollview () { HasVerticalScroller = true, HasHorizontalScroller = false, DocumentView = toolboxWidget @@ -261,43 +251,9 @@ public MacToolbox (ToolboxService toolboxService, IPadWindow container) AddSubview (messageTextField); keyViewLoopDelegate.AddViews (filterEntry, catToggleButton, compactModeToggleButton, toolboxAddButton, toolboxWidget); + keyViewLoopDelegate.RecalculeNextResponderChain (); } - #region InternalKeyLoop - - private void FilterEntry_CommandRaised (object sender, NativeViews.SearchTextFieldCommand e) - { - switch (e) { - case NativeViews.SearchTextFieldCommand.InsertBacktab: - keyViewLoopDelegate.FocusNextView ((NSView)sender, -1); - break; - case NativeViews.SearchTextFieldCommand.InsertTab: - keyViewLoopDelegate.FocusNextView ((NSView)sender, 1); - break; - } - } - - private void OnKeyDownKeyLoop (object sender, NativeViews.NSEventArgs args) - { - if (sender is NSView view && keyViewLoopDelegate.Contains (view)) { - if (args.Event.KeyCode == (int)KeyCodes.Tab) { - - if ((int)args.Event.ModifierFlags == (int)KeyModifierFlag.None) { - keyViewLoopDelegate.FocusNextView (view, 1); - args.Handled = true; - return; - } - if ((int)args.Event.ModifierFlags == (int)KeyModifierFlag.Shift) { - keyViewLoopDelegate.FocusNextView (view, -1); - args.Handled = true; - return; - } - } - } - } - - #endregion - NSIndexPath GetFirstVisibleItemIndexPath () { for (int i = 0; i < toolboxWidget.CategoryVisibilities.Count; i++) { @@ -323,7 +279,6 @@ private void ToolboxWidget_KeyDownPressed (object sender, NativeViews.NSEventArg return; } } - OnKeyDownKeyLoop (sender, args); } void SetCustomMessage (string value) @@ -482,7 +437,6 @@ internal void OnUpdateDeleteItem (CommandInfo info) #region GUI population - readonly List items = new List (); Dictionary categories = new Dictionary (); void AddItems (IEnumerable nodes) @@ -534,6 +488,7 @@ public void Refresh () compactModeToggleButton.Hidden = !toolboxWidget.CanIconizeToolboxCategories; compactModeToggleButton.InvalidateIntrinsicContentSize (); + keyViewLoopDelegate.RecalculeNextResponderChain (); if (categories.Count == 0) { SetCustomMessage (GettextCatalog.GetString ("There are no tools available for the current document.")); @@ -553,22 +508,13 @@ protected override void Dispose (bool disposing) if (disposing) { filterEntry.Activated -= FilterTextChanged; - filterEntry.CommandRaised -= FilterEntry_CommandRaised; - catToggleButton.Activated -= ToggleCategorisation; - catToggleButton.KeyDownPressed -= OnKeyDownKeyLoop; - compactModeToggleButton.Activated -= ToggleCompactMode; - compactModeToggleButton.KeyDownPressed -= OnKeyDownKeyLoop; - toolboxAddButton.Activated -= ToolboxAddButton_Clicked; - toolboxAddButton.KeyDownPressed -= OnKeyDownKeyLoop; - toolboxWidget.ActivateSelectedItem -= ToolboxWidget_ActivateSelectedItem; toolboxWidget.MenuOpened -= ToolboxWidget_MenuOpened; toolboxWidget.DragBegin -= ToolboxWidget_DragBegin; toolboxWidget.RegionCollapsed -= FilterTextChanged; - toolboxWidget.KeyDownPressed -= OnKeyDownKeyLoop; toolboxService.ToolboxContentsChanged -= ToolboxService_ToolboxContentsChanged; toolboxService.ToolboxConsumerChanged -= ToolboxService_ToolboxConsumerChanged; @@ -614,6 +560,7 @@ public bool AllowEditingComponents { } set { toolboxAddButton.Hidden = !value; + keyViewLoopDelegate.RecalculeNextResponderChain (); toolboxAddButton.InvalidateIntrinsicContentSize (); } } diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/SearchTextField.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/SearchTextField.cs index 90d0e6f7d02..a6d0ff6aa08 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/SearchTextField.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/SearchTextField.cs @@ -33,20 +33,13 @@ namespace MonoDevelop.DesignerSupport.Toolbox.NativeViews { - enum SearchTextFieldCommand - { - InsertTab, - InsertBacktab - } - - class SearchTextField : NSSearchField, INSSearchFieldDelegate + class SearchTextField : NSSearchField { public event EventHandler Focused; - public event EventHandler CommandRaised; public SearchTextField () { - Delegate = this; + } public override bool BecomeFirstResponder () @@ -54,21 +47,6 @@ public override bool BecomeFirstResponder () Focused?.Invoke (this, EventArgs.Empty); return base.BecomeFirstResponder (); } - - [Export ("control:textView:doCommandBySelector:")] - bool CommandBySelector (NSControl control, NSTextField field, ObjCRuntime.Selector sel) - { - switch (sel.Name) { - case "insertTab:": // down arrow - CommandRaised?.Invoke (this, SearchTextFieldCommand.InsertTab); - return true; - - case "insertBacktab:": // up arrow - CommandRaised?.Invoke (this, SearchTextFieldCommand.InsertBacktab); - return true; - } - return false; - } } } #endif \ No newline at end of file diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ToggleButton.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ToggleButton.cs index 3bcb58a0411..aa3cb5a8e38 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ToggleButton.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ToggleButton.cs @@ -47,7 +47,6 @@ public NSEventArgs (NSEvent nsEvent) class ToggleButton : NSButton { - public event EventHandler KeyDownPressed; public event EventHandler Focused; public override CGSize IntrinsicContentSize => Hidden ? CGSize.Empty : new CGSize (25, 25); @@ -78,12 +77,6 @@ public override void KeyDown (NSEvent theEvent) if ((int)theEvent.ModifierFlags == (int) KeyModifierFlag.None && (theEvent.KeyCode == (int)KeyCodes.Enter || theEvent.KeyCode == (int)KeyCodes.Space)) { PerformClick (this); } - - var args = new NSEventArgs (theEvent); - KeyDownPressed?.Invoke (this, args); - - if (!args.Handled) - base.KeyDown (theEvent); } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs index f5c475a6831..ca9a648099c 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NativeViewHelper.cs @@ -32,9 +32,22 @@ namespace MonoDevelop.Components.Mac { + internal class UnfocusableScrollview : NSScrollView + { + public override bool AcceptsFirstResponder () => false; + } + + internal class UnfocusableStackView : NSStackView + { + public override bool AcceptsFirstResponder () + { + return false; + } + } + static class NativeViewHelper { - public static NSStackView CreateVerticalStackView (int spacing = 10, bool translatesAutoresizingMaskIntoConstraints = false) => new NSStackView () { + public static NSStackView CreateVerticalStackView (int spacing = 10, bool translatesAutoresizingMaskIntoConstraints = false) => new UnfocusableStackView () { Orientation = NSUserInterfaceLayoutOrientation.Vertical, Alignment = NSLayoutAttribute.Leading, Spacing = spacing, @@ -42,7 +55,7 @@ static class NativeViewHelper TranslatesAutoresizingMaskIntoConstraints = translatesAutoresizingMaskIntoConstraints }; - public static NSStackView CreateHorizontalStackView (int spacing = 10) => new NSStackView () { + public static NSStackView CreateHorizontalStackView (int spacing = 10) => new UnfocusableStackView () { Orientation = NSUserInterfaceLayoutOrientation.Horizontal, Alignment = NSLayoutAttribute.CenterY, Spacing = spacing, From 7b034feef35662b949510f6fa2656c1d0998e83c Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 24 Oct 2019 21:28:33 +0200 Subject: [PATCH 20/30] Fixes call to KeyDown and sets corrects the selected view if was the case --- .../CommandManager.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 2668eebd56f..70a496c71e9 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -511,14 +511,19 @@ firstResponder is AppKit.NSView view && view != window.ContentView) { if (currentEvent.KeyCode == (ushort)AppKit.NSKey.Tab) { - view = FindValidKeyView (view); + + var expectedKeyView = FindValidKeyView (view); AppKit.NSView next = null; if (currentEvent.ModifierFlags.HasFlag (AppKit.NSEventModifierMask.ShiftKeyMask)) { - next = view.PreviousValidKeyView; + next = expectedKeyView.PreviousValidKeyView; } else { - next = view.NextValidKeyView; + next = expectedKeyView.NextValidKeyView; + } + + view.KeyDown (currentEvent); + if (next != null && window?.FirstResponder != next) { + window.MakeFirstResponder (next); } - window.MakeFirstResponder (next); } else { view.KeyDown (currentEvent); } From 95e8772268c7445e9fcd39f3725add4c05887a39 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 24 Oct 2019 21:35:23 +0200 Subject: [PATCH 21/30] Renames ShowToolbar o ShowHeader for consistency with property --- .../MonoDevelop.DesignerSupport/MacPropertyGrid.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 642d95be1cb..85288ec65c7 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -120,7 +120,7 @@ public object CurrentObject { NSTableView internalTableView; NSView border; - void ShowToolbar (bool enabled) + void ShowHeader (bool enabled) { var topConstraint = propertyEditorPanel.Constraints.FirstOrDefault (s => s.FirstItem == propertyList && s.FirstAttribute == NSLayoutAttribute.Top); propertyEditorPanel.RemoveConstraint (topConstraint); @@ -141,7 +141,7 @@ public bool ToolbarVisible { get => !header.Hidden; set { //we ensure remove current constraints from proppy - ShowToolbar (value); + ShowHeader (value); } } From 38f32766300d217e73b97dcb86dd8f9e02029a13 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 24 Oct 2019 21:37:26 +0200 Subject: [PATCH 22/30] Task.FromResult () to use generic --- .../NativePropertyEditor/ComponentModelObjectEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs index 68adeb695e5..84fe8bdeea3 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs @@ -83,7 +83,7 @@ public Task GetAssignableTypesAsync (IPropertyInfo proper public Task> GetHandlersAsync (IEventInfo ev) => Task.FromResult(defaultHandlerList); - public Task GetNameAsync () => Task.FromResult ((string) null); + public Task GetNameAsync () => Task.FromResult (null); public Task> GetPropertyVariantsAsync (IPropertyInfo property) => Task.FromResult> (Array.Empty ()); From 752a23f98729fe0353ed4d4d500b05531da97648 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Fri, 25 Oct 2019 13:55:13 +0200 Subject: [PATCH 23/30] Moves the logic handling keydown events to CommandManager instead GtkNSViewHost --- .../CommandManager.cs | 14 +++++++++++ .../Mac/GtkNSViewHost.cs | 25 ------------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 70a496c71e9..6f7d390c1d0 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -453,6 +453,8 @@ void OnKeyReleased (object o, Gtk.KeyReleaseEventArgs e) var window = currentEvent?.Window; var firstResponder = window?.FirstResponder; + bool retVal = false; + // GTK eats FlagsChanged events and this is just to inform // modifier keys changed state, hence always send it to // focused view @@ -467,10 +469,22 @@ void OnKeyReleased (object o, Gtk.KeyReleaseEventArgs e) // KeyboardShortcut[] accels = KeyBindingManager.AccelsFromKey (e.Event, out complete); + if (currentEvent != null && + currentEvent.Type == AppKit.NSEventType.KeyUp && + firstResponder is AppKit.NSView view && + view != window.ContentView) { + + view.KeyUp (currentEvent); + + retVal = true; + } + if (!complete) { // incomplete accel NotifyIncompleteKeyReleased (e.Event); } + + e.RetVal = retVal; } internal bool ProcessKeyEvent (Gdk.EventKey ev) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs index 61c06c4b806..eec5dac574f 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs @@ -379,31 +379,6 @@ bool ForwardEvent ( return baseCall (evnt); } - protected override bool OnKeyPressEvent (Gdk.EventKey evnt) - { - LogEnter (); - try { - return ForwardEvent ( - evnt, - (v, e) => v.KeyDown (e), - base.OnKeyReleaseEvent); - } finally { - LogExit (); - } - } - - protected override bool OnKeyReleaseEvent (Gdk.EventKey evnt) - { - LogEnter (); - try { - return ForwardEvent ( - evnt, - (v, e) => v.KeyUp (e), - base.OnKeyReleaseEvent); - } finally { - LogExit (); - } - } #region Tracing From d53aab0d7008e0b20d0965e4ddff7475df4a9f7c Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Sat, 26 Oct 2019 13:32:08 +0200 Subject: [PATCH 24/30] Moves all the simulation in keydown into a method --- .../CommandManager.cs | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 6f7d390c1d0..60031b4edc1 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -524,29 +524,33 @@ internal bool ProcessKeyEvent (Gdk.EventKey ev) firstResponder is AppKit.NSView view && view != window.ContentView) { - if (currentEvent.KeyCode == (ushort)AppKit.NSKey.Tab) { - - var expectedKeyView = FindValidKeyView (view); - AppKit.NSView next = null; - if (currentEvent.ModifierFlags.HasFlag (AppKit.NSEventModifierMask.ShiftKeyMask)) { - next = expectedKeyView.PreviousValidKeyView; - } else { - next = expectedKeyView.NextValidKeyView; - } - - view.KeyDown (currentEvent); - if (next != null && window?.FirstResponder != next) { - window.MakeFirstResponder (next); - } - } else { - view.KeyDown (currentEvent); - } + SimulateKeyDownInView (view, currentEvent, window); + return true; } #endif return false; } + void SimulateKeyDownInView (AppKit.NSView view, AppKit.NSEvent currentEvent, AppKit.NSWindow window) + { + if (currentEvent.KeyCode == (ushort)AppKit.NSKey.Tab) { + var expectedKeyView = FindValidKeyView (view); + AppKit.NSView next = null; + if (currentEvent.ModifierFlags.HasFlag (AppKit.NSEventModifierMask.ShiftKeyMask)) { + next = expectedKeyView.PreviousValidKeyView; + } else { + next = expectedKeyView.NextValidKeyView; + } + + view.KeyDown (currentEvent); + if (next != null && window?.FirstResponder != next) { + window.MakeFirstResponder (next); + } + } else { + view.KeyDown (currentEvent); + } + } static AppKit.NSView FindValidKeyView (AppKit.NSView view) { From fdf3b93ccb2a5a0ac8782caed89852527edb2f01 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Sat, 26 Oct 2019 14:51:35 +0200 Subject: [PATCH 25/30] =?UTF-8?q?Adds=20a=20prototype=20simulation=20of=20?= =?UTF-8?q?default=20action=20behavior=20in=20basic=20types=20Fixes=20VSTS?= =?UTF-8?q?=20#1001627=20-=20A11Y=5FXamarin=20Designers=5FProperty=20pane?= =?UTF-8?q?=5Fkeyboard=20:=20User=20is=20unable=20to=20open=20the=20?= =?UTF-8?q?=E2=80=9CEdit=E2=80=9D=20button=20by=20using=20space/enter=20ke?= =?UTF-8?q?ys=20Fixes=20VSTS=20#1001625=20-=20A11Y=5FXamarin=20Designers?= =?UTF-8?q?=5FProperty=20pane=5Fkeyboard=20:=20User=20is=20unable=20to=20c?= =?UTF-8?q?heck/uncheck=20the=20=E2=80=9CAutomatic=20tree=E2=80=9D=20check?= =?UTF-8?q?=20box=20by=20using=20space=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MonoDevelop.Components.Commands/CommandManager.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 60031b4edc1..7d236d441fc 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -437,6 +437,13 @@ bool IsCommandBinding (object commandId, string binding) } return false; } + + private void SimulateViewKeyActionBehaviour (AppKit.NSView view, AppKit.NSEvent currentEvent) + { + if (view is AppKit.NSButton btn && (currentEvent.KeyCode == (ushort)AppKit.NSKey.Space || currentEvent.KeyCode == (ushort)AppKit.NSKey.Return)) { + btn.PerformClick (btn); + } + } #endif [GLib.ConnectBefore] @@ -475,7 +482,7 @@ firstResponder is AppKit.NSView view && view != window.ContentView) { view.KeyUp (currentEvent); - + SimulateViewKeyActionBehaviour (view, currentEvent); retVal = true; } From 1df605968cbe844e48f91f717b1628ac579d74d1 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Sat, 26 Oct 2019 14:52:28 +0200 Subject: [PATCH 26/30] moves mac specific code to a mac compilation region code --- .../CommandManager.cs | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 7d236d441fc..59acd526a8b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -438,12 +438,48 @@ bool IsCommandBinding (object commandId, string binding) return false; } + void SimulateKeyDownInView (AppKit.NSView view, AppKit.NSEvent currentEvent, AppKit.NSWindow window) + { + if (currentEvent.KeyCode == (ushort)AppKit.NSKey.Tab) { + var expectedKeyView = FindValidKeyView (view); + AppKit.NSView next = null; + if (currentEvent.ModifierFlags.HasFlag (AppKit.NSEventModifierMask.ShiftKeyMask)) { + next = expectedKeyView.PreviousValidKeyView; + } else { + next = expectedKeyView.NextValidKeyView; + } + + view.KeyDown (currentEvent); + if (next != null && window?.FirstResponder != next) { + window.MakeFirstResponder (next); + } + } else { + view.KeyDown (currentEvent); + } + } + private void SimulateViewKeyActionBehaviour (AppKit.NSView view, AppKit.NSEvent currentEvent) { if (view is AppKit.NSButton btn && (currentEvent.KeyCode == (ushort)AppKit.NSKey.Space || currentEvent.KeyCode == (ushort)AppKit.NSKey.Return)) { btn.PerformClick (btn); } } + + static AppKit.NSView FindValidKeyView (AppKit.NSView view) + { + if (view == null) + return null; + + if (view.AcceptsFirstResponder ()) { + if (view.Superview?.Superview is AppKit.NSControl control && control.CurrentEditor == view) { + return FindValidKeyView (control); + } + return view; + } + + return FindValidKeyView (view.Superview); + } + #endif [GLib.ConnectBefore] @@ -539,41 +575,6 @@ firstResponder is AppKit.NSView view && return false; } - void SimulateKeyDownInView (AppKit.NSView view, AppKit.NSEvent currentEvent, AppKit.NSWindow window) - { - if (currentEvent.KeyCode == (ushort)AppKit.NSKey.Tab) { - var expectedKeyView = FindValidKeyView (view); - AppKit.NSView next = null; - if (currentEvent.ModifierFlags.HasFlag (AppKit.NSEventModifierMask.ShiftKeyMask)) { - next = expectedKeyView.PreviousValidKeyView; - } else { - next = expectedKeyView.NextValidKeyView; - } - - view.KeyDown (currentEvent); - if (next != null && window?.FirstResponder != next) { - window.MakeFirstResponder (next); - } - } else { - view.KeyDown (currentEvent); - } - } - - static AppKit.NSView FindValidKeyView (AppKit.NSView view) - { - if (view == null) - return null; - - if (view.AcceptsFirstResponder ()) { - if (view.Superview?.Superview is AppKit.NSControl control && control.CurrentEditor == view) { - return FindValidKeyView (control); - } - return view; - } - - return FindValidKeyView (view.Superview); - } - bool ProcessKeyEventCore (Gdk.EventKey ev) { if (!IsEnabled) From a5ce42c27e9a52ad2e9477684c244dbe51fe2a49 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 30 Oct 2019 19:25:01 +0100 Subject: [PATCH 27/30] Removes some obsolete code in GtkNSViewHost --- .../Mac/GtkNSViewHost.cs | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs index eec5dac574f..37c7ded0b0f 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs @@ -52,9 +52,6 @@ public sealed class GtkNSViewHost : Widget [DllImport (LIBGTKQUARTZ)] static extern IntPtr gdk_quartz_window_get_nsview (IntPtr window); - [DllImport (LIBGTKQUARTZ)] - static extern IntPtr gdk_quartz_event_get_nsevent (IntPtr evnt); - [DllImport (LIBGTKQUARTZ)] static extern void gdk_window_coords_to_parent ( IntPtr window, @@ -66,15 +63,6 @@ static extern void gdk_window_coords_to_parent ( [DllImport (LIBGTKQUARTZ)] static extern bool gdk_window_has_native (IntPtr window); - static NSEvent GetNSEvent (Gdk.Event evnt) - { - if (evnt == null || evnt.Handle == IntPtr.Zero) - return null; - - var nsEventHandle = gdk_quartz_event_get_nsevent (evnt.Handle); - return Runtime.GetNSObject (nsEventHandle); - } - NSView view; NSView superview; bool disposeViewOnGtkDestroy; @@ -361,25 +349,6 @@ protected override bool OnWidgetEvent (Gdk.Event evnt) } } - bool ForwardEvent ( - TEvent evnt, - Action forwardCall, - Func baseCall) where TEvent : Gdk.Event - { - var acceptsFirstResponderView = GetAcceptsFirstResponderView (); - if (acceptsFirstResponderView == null) - return false; - - var nsEvent = GetNSEvent (evnt); - if (nsEvent == null) - return false; - - forwardCall (acceptsFirstResponderView, nsEvent); - - return baseCall (evnt); - } - - #region Tracing int traceDepth; From 09febd9ea8fe1912ecc5805bd10fafcf09825604 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 30 Oct 2019 19:34:37 +0100 Subject: [PATCH 28/30] Removes unnecessary allocation checking subviews --- .../MonoDevelop.DesignerSupport/MacPropertyGrid.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 85288ec65c7..82cd14722f9 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -73,9 +73,10 @@ public MacPropertyGrid () #region Header Proppy Hack - header = propertyEditorPanel.Subviews [0]; - propertyList = propertyEditorPanel.Subviews [1]; - internalTableView = propertyList.Subviews.OfType () + var subviews = propertyEditorPanel.Subviews; + header = subviews [0]; + propertyList = subviews [1]; + internalTableView = subviews.OfType () .FirstOrDefault ().DocumentView as NSTableView; //we need the second item constrained with the property list From 3904854dcdda5896aba99883be2308c8cfb1943e Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Wed, 30 Oct 2019 23:09:03 +0100 Subject: [PATCH 29/30] Fixes issue introduced in latest changes --- .../MonoDevelop.DesignerSupport/MacPropertyGrid.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs index 82cd14722f9..245bfdab97f 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/MacPropertyGrid.cs @@ -76,7 +76,7 @@ public MacPropertyGrid () var subviews = propertyEditorPanel.Subviews; header = subviews [0]; propertyList = subviews [1]; - internalTableView = subviews.OfType () + internalTableView = propertyList.Subviews.OfType () .FirstOrDefault ().DocumentView as NSTableView; //we need the second item constrained with the property list From a56b550d686aa65bf2f816f1f852517ff0afba54 Mon Sep 17 00:00:00 2001 From: Jose Medrano Date: Thu, 31 Oct 2019 10:22:41 +0100 Subject: [PATCH 30/30] Don't saves values in cases where value doesn't change --- .../NativePropertyEditor/ComponentModelObjectEditor.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs index 84fe8bdeea3..edd4971fe59 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/NativePropertyEditor/ComponentModelObjectEditor.cs @@ -114,6 +114,16 @@ public Task SetValueAsync (IPropertyInfo propertyInfo, ValueInfo value, Pr return Task.FromException (new ArgumentNullException (nameof (propertyInfo))); if (propertyInfo is DescriptorPropertyInfo info && info.CanWrite) { + + var actualValue = info.GetValue (this.Target); + if (info.GetValue (this.Target).Equals (value.Value)) { + return Task.CompletedTask; + } + + //this is an exception for null/empty cases of string + if (typeof (T) == typeof(string) && string.IsNullOrEmpty (actualValue as string) && string.IsNullOrEmpty (value.Value as string)) { + return Task.CompletedTask; + } info.SetValue (this.Target, value.Value); RaisePropertyChanged (info); } else {