Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xamarin/Xamarin.PropertyEditing.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Maupin <ermaup@microsoft.com>2019-07-04 01:34:48 +0300
committerGitHub <noreply@github.com>2019-07-04 01:34:48 +0300
commitf77ce63e6566dfeaa9ca3a70a619870a251be78f (patch)
tree6697c0c6f7cd291577c8198d7c7a1b31ffb96c02 /Xamarin.PropertyEditing.Mac/Controls
parent98584081ea54226fe486977032f8e2dd93f62fca (diff)
parenta2c5c82cc22edaea46b0eeadeb982a9ac5fe75f7 (diff)
Merge pull request #561 from xamarin/dominique-BindingDialog
[Mac] Initial Binding Editor Dialog.
Diffstat (limited to 'Xamarin.PropertyEditing.Mac/Controls')
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BaseSelectorOutlineView.cs38
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs569
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs78
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs178
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceOutlineView.cs139
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs78
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs139
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs47
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/ObjectOutlineView.cs140
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/PathOutlineView.cs168
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs5
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs31
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs10
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs36
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs39
15 files changed, 1663 insertions, 32 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BaseSelectorOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BaseSelectorOutlineView.cs
new file mode 100644
index 0000000..e18c197
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BaseSelectorOutlineView.cs
@@ -0,0 +1,38 @@
+using System;
+using AppKit;
+using Foundation;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BaseSelectorOutlineView : NSOutlineView
+ {
+ public BaseSelectorOutlineView ()
+ {
+ Initialize ();
+ }
+
+ // Called when created from unmanaged code
+ public BaseSelectorOutlineView (IntPtr handle) : base (handle)
+ {
+ Initialize ();
+ }
+
+ // Called when created directly from a XIB file
+ [Export ("initWithCoder:")]
+ public BaseSelectorOutlineView (NSCoder coder) : base (coder)
+ {
+ Initialize ();
+ }
+
+ public override bool ValidateProposedFirstResponder (NSResponder responder, NSEvent forEvent)
+ {
+ return true;
+ }
+
+ private void Initialize ()
+ {
+ HeaderView = null;
+ TranslatesAutoresizingMaskIntoConstraints = false;
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs
new file mode 100644
index 0000000..f41673f
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs
@@ -0,0 +1,569 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using AppKit;
+using CoreGraphics;
+using Foundation;
+using Xamarin.PropertyEditing.Common;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingEditorWindow : NSPanel
+ {
+ private NSButton buttonDone;
+ private NSButton buttonCancel;
+
+ private NSPopUpButton bindingTypePopup;
+
+ private NSPopUpButton valueConverterPopup;
+
+ private NSButton addConverterButton;
+
+ private NSView ancestorTypeBox;
+
+ private NSView mainContainer;
+ private NSView bindingPropertiesView;
+ private NSView flagsPropertiesView;
+ private NSButton buttonMoreSettings;
+
+ private nfloat MoreSettingsViewHeight { get; set; }
+
+ private const float AddConverterButtonSize = 20;
+
+ private new ModalWindowCloseDelegate Delegate
+ {
+ get => (ModalWindowCloseDelegate)base.Delegate;
+ set => base.Delegate = value;
+ }
+
+ private readonly PropertyEditorSelector editorSelector = new PropertyEditorSelector ();
+
+ private const string BindingPropertiesIdentifier = "BindingProperties";
+ private const string FlagPropertiesIdentifier = "FlagProperties";
+ internal const float HeaderHeight = 28f;
+
+ internal CreateBindingViewModel ViewModel { get; }
+
+ private HeaderView typeHeader;
+
+ private UnfocusableTextField longDescription;
+ private UnfocusableTextField labelOtherSettings;
+ private TypeSelectorControl typeSelectorControl;
+
+ private nfloat heightConstant, titleBarHeight;
+
+ private NSLayoutConstraint ancestorTypeBoxHeightConstraint;
+ private NSLayoutConstraint bindingPropertiesViewHeightConstraint;
+
+ private BindingPathSelectorControl pathSelectorControl;
+
+ internal BindingEditorWindow (IHostResourceProvider hostResources, PropertyViewModel propertyViewModel)
+ : base (new CGRect (0, 0, 728, 445), NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Resizable, NSBackingStore.Buffered, true)
+ {
+ if (hostResources == null)
+ throw new ArgumentNullException (nameof (hostResources));
+ if (propertyViewModel == null)
+ throw new ArgumentNullException (nameof (propertyViewModel));
+
+ ViewModel = new CreateBindingViewModel (propertyViewModel.TargetPlatform, propertyViewModel.Editors.Single (), propertyViewModel.Property, includeAddValueConverter: false);
+
+ Delegate = new ModalWindowCloseDelegate ();
+
+ FloatingPanel = true;
+
+ MaxSize = new CGSize (960, 720); // TODO discuss what the Max/Min Size should be and if we should have one.
+ MinSize = new CGSize (320, 240);
+
+ this.mainContainer = new NSView {
+ TranslatesAutoresizingMaskIntoConstraints = false
+ };
+
+ this.buttonDone = new NSButton {
+ BezelStyle = NSBezelStyle.Rounded,
+ ControlSize = NSControlSize.Regular,
+ Highlighted = true,
+ KeyEquivalent = "\r", // Fire when enter pressed
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.mainContainer.AddSubview (this.buttonDone);
+
+ this.buttonCancel = new NSButton {
+ BezelStyle = NSBezelStyle.Rounded,
+ ControlSize = NSControlSize.Regular,
+ Title = Properties.Resources.Cancel,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.buttonCancel.Activated += (sender, e) => {
+ Delegate.Response = NSModalResponse.Cancel;
+ Close ();
+ };
+
+ this.mainContainer.AddSubview (this.buttonCancel);
+
+ var bindingTypeLabel = new UnfocusableTextField {
+ Alignment = NSTextAlignment.Right,
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13),
+ StringValue = Properties.Resources.BindingType + ":",
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.mainContainer.AddSubview (bindingTypeLabel);
+
+ this.bindingTypePopup = new FocusablePopUpButton {
+ ControlSize = NSControlSize.Regular,
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13),
+ StringValue = String.Empty,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ var bindingTypeMenuList = new NSMenu ();
+ this.bindingTypePopup.Menu = bindingTypeMenuList;
+ this.mainContainer.AddSubview (this.bindingTypePopup);
+
+ var valueConverterLabel = new UnfocusableTextField {
+ Alignment = NSTextAlignment.Right,
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13),
+ StringValue = Properties.Resources.Converter + ":",
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.ancestorTypeBox = new NSView {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ WantsLayer = true,
+
+ // Layer out of alphabetical order so that WantsLayer creates the layer first
+ Layer = {
+ CornerRadius = 1.0f,
+ BorderColor = new CGColor (.5f, .5f, .5f, 1.0f),
+ BorderWidth = 1,
+ },
+ };
+
+ this.mainContainer.AddSubview (this.ancestorTypeBox);
+
+ this.mainContainer.AddSubview (valueConverterLabel);
+
+ this.valueConverterPopup = new FocusablePopUpButton {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ StringValue = String.Empty,
+ ControlSize = NSControlSize.Regular,
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13),
+ };
+
+ var valueConverterMenuList = new NSMenu ();
+ this.valueConverterPopup.Menu = valueConverterMenuList;
+ this.mainContainer.AddSubview (this.valueConverterPopup);
+
+ this.addConverterButton = new CommandButton {
+ BezelStyle = NSBezelStyle.Rounded,
+ Command = ViewModel.RequestAddValueConverterCommand,
+ Image = NSImage.ImageNamed (NSImageName.AddTemplate),
+ Title = string.Empty,
+ ToolTip = Properties.Resources.AddValueConverterEllipsis,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.mainContainer.AddSubview (this.addConverterButton);
+
+ this.buttonMoreSettings = new NSButton {
+ BezelStyle = NSBezelStyle.Disclosure,
+ Title = string.Empty,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+ this.buttonMoreSettings.SetButtonType (NSButtonType.PushOnPushOff);
+
+ this.mainContainer.AddSubview (this.buttonMoreSettings);
+
+ this.labelOtherSettings = new UnfocusableTextField {
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13),
+ StringValue = Properties.Resources.OtherSettings,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.mainContainer.AddSubview (this.labelOtherSettings);
+
+ this.bindingPropertiesView = new NSView {
+ Hidden = true,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ WantsLayer = true,
+
+ // Layer out of alphabetical order so that WantsLayer creates the layer first
+ Layer = {
+ CornerRadius = 1.0f,
+ BorderColor = new CGColor (.5f, .5f, .5f, .5f),
+ BorderWidth = 1,
+ },
+ };
+
+ this.mainContainer.AddSubview (this.bindingPropertiesView);
+
+ this.flagsPropertiesView = new NSView {
+ Hidden = true,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ WantsLayer = true,
+
+ // Layer out of alphabetical order so that WantsLayer creates the layer first
+ Layer = {
+ CornerRadius = 1.0f,
+ BorderColor = new CGColor (.5f, .5f, .5f, .5f),
+ BorderWidth = 1,
+ },
+ };
+
+ this.mainContainer.AddSubview (this.flagsPropertiesView);
+
+ //Work out the titlebar height
+ this.titleBarHeight = Frame.Size.Height - ContentRectFor (Frame).Size.Height;
+
+ this.ancestorTypeBoxHeightConstraint = NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Bottom, 1f, -145f);
+ this.heightConstant = this.ancestorTypeBoxHeightConstraint.Constant;
+
+ this.bindingPropertiesViewHeightConstraint = NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 124);
+
+ this.buttonMoreSettings.Activated += OnButtonMoreSettingsToggled;
+
+ this.pathSelectorControl = new BindingPathSelectorControl (ViewModel);
+ this.mainContainer.AddSubview (this.pathSelectorControl);
+
+ this.mainContainer.AddConstraints (new[] {
+ NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingTypePopup, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Left, 1f, 21f),
+ NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20),
+
+ NSLayoutConstraint.Create (this.bindingTypePopup, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Top, 1f, 18f),
+ NSLayoutConstraint.Create (this.bindingTypePopup, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Right, 1f, 10f),
+
+ NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingTypePopup, NSLayoutAttribute.Bottom, 1f, 18f),
+ NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Left, 1f, -8f),
+ this.ancestorTypeBoxHeightConstraint,
+
+ NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Right, 1f, -21f),
+ NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, -30f),
+ NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal,this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, 0f),
+
+ NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Bottom, 1f, 22f),
+ NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20),
+
+ NSLayoutConstraint.Create (this.valueConverterPopup, NSLayoutAttribute.Top, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.valueConverterPopup, NSLayoutAttribute.Left, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Right, 1f, 10f),
+ NSLayoutConstraint.Create (this.valueConverterPopup, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, -AddConverterButtonSize - 83), // TODO Need a better calculation here
+
+ NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.valueConverterPopup, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Right, NSLayoutRelation.Equal,this.ancestorTypeBox, NSLayoutAttribute.Right, 1f, 0f),
+ NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, AddConverterButtonSize),
+ NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, AddConverterButtonSize),
+
+ NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Top, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Bottom, 1f, 18f),
+ NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, -5f),
+ NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20),
+ NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, 20),
+
+ NSLayoutConstraint.Create (this.labelOtherSettings, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.buttonMoreSettings, NSLayoutAttribute.Top, 1f, -1f),
+ NSLayoutConstraint.Create (this.labelOtherSettings, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.buttonMoreSettings, NSLayoutAttribute.Right, 1f, 0f),
+ NSLayoutConstraint.Create (this.labelOtherSettings, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20),
+
+ NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.buttonMoreSettings, NSLayoutAttribute.Bottom, 1f, 10f),
+ NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Left, 1f, -8f),
+ bindingPropertiesViewHeightConstraint,
+ NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f),
+
+ NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Right, 1f, 0f),
+ NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Height, 1f, 0f),
+
+ NSLayoutConstraint.Create (this.buttonDone, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Bottom, 1f, -44f),
+ NSLayoutConstraint.Create (this.buttonDone, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Right, 1f, 0f),
+ NSLayoutConstraint.Create (this.buttonDone, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f),
+
+ NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.buttonDone, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.buttonDone, NSLayoutAttribute.Left, 1f, -10f),
+ NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f),
+ });
+
+ // put the MainContainer inside this panel's ContentView
+ ContentView.AddSubview (this.mainContainer);
+
+ ContentView.AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Left, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Height, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Height, 1f, 0f),
+ NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Width, 1f, 0f),
+
+ });
+
+ Title = ViewModel.PropertyDisplay;
+ this.buttonDone.Title = Properties.Resources.CreateBindingTitle;
+ this.buttonDone.Enabled = ViewModel.CanCreateBinding;
+
+ ViewModel.BindingSources.Task.ContinueWith (t => {
+ foreach (BindingSource item in ViewModel.BindingSources.Value) {
+ this.bindingTypePopup.Menu.AddItem (new NSMenuItem (item.Name) {
+ RepresentedObject = new NSObjectFacade (item)
+ });
+ }
+ }, TaskScheduler.FromCurrentSynchronizationContext ());
+
+ this.bindingTypePopup.Activated += (o, e) => {
+ if (this.bindingTypePopup.Menu.HighlightedItem.RepresentedObject is NSObjectFacade facade) {
+ ViewModel.SelectedBindingSource = (BindingSource)facade.Target;
+ }
+ };
+
+ this.valueConverterPopup.Activated += (o, e) => {
+ if (this.valueConverterPopup.Menu.HighlightedItem.RepresentedObject is NSObjectFacade facade) {
+ ViewModel.SelectedValueConverter = (Resource)facade.Target;
+ }
+ };
+
+ RepopulateValueConverterPopup ();
+
+ this.typeHeader = new HeaderView {
+ Title = Properties.Resources.Type,
+ };
+
+ this.ancestorTypeBox.AddSubview (this.typeHeader);
+
+ this.ancestorTypeBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, HeaderHeight),
+ });
+
+ this.typeSelectorControl = new TypeSelectorControl {
+ Flush = true,
+ Hidden = true,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.ancestorTypeBox.AddSubview (this.typeSelectorControl);
+
+ this.ancestorTypeBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.typeHeader, NSLayoutAttribute.Bottom, 1f, 0f),
+ NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, -10f)
+ });
+
+ var resourceSelectorControl = new BindingResourceSelectorControl (ViewModel) {
+ Hidden = true,
+ };
+
+ this.ancestorTypeBox.AddSubview (resourceSelectorControl);
+
+ this.ancestorTypeBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, 0f)
+ });
+
+ var objectSelectorControl = new BindingObjectSelectorControl (ViewModel) {
+ Hidden = true,
+ };
+
+ this.ancestorTypeBox.AddSubview (objectSelectorControl);
+
+ this.ancestorTypeBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, 0f)
+ });
+
+ this.longDescription = new UnfocusableTextField {
+ Alignment = NSTextAlignment.Left,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ StringValue = string.Empty,
+ };
+
+ this.ancestorTypeBox.AddSubview (this.longDescription);
+
+ this.ancestorTypeBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 10f),
+ NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 10f),
+ NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, -10f),
+ NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24),
+ });
+
+ ViewModel.PropertyChanged += OnPropertyChanged;
+
+ ViewModel.CreateValueConverterRequested += OnCreateValueConverterRequested;
+
+ this.buttonDone.Activated += OnButtonDoneActivated;
+
+ CreateMorePropertiesEditors (hostResources);
+ }
+
+ private void OnButtonDoneActivated (object sender, EventArgs e)
+ {
+ if (!string.IsNullOrEmpty (this.pathSelectorControl.CustomPath)) {
+ ViewModel.Path = this.pathSelectorControl.CustomPath;
+ }
+ Delegate.Response = NSModalResponse.OK;
+ Close ();
+ }
+
+
+ private void OnButtonMoreSettingsToggled (object sender, EventArgs e)
+ {
+ if (sender is NSButton moreButton) {
+ this.bindingPropertiesView.Hidden = moreButton.State == NSCellStateValue.Off;
+ this.flagsPropertiesView.Hidden = this.bindingPropertiesView.Hidden;
+
+ this.bindingPropertiesViewHeightConstraint.Constant = this.MoreSettingsViewHeight;
+ this.ancestorTypeBoxHeightConstraint.Constant = this.bindingPropertiesView.Hidden ? this.heightConstant : this.heightConstant - (MoreSettingsViewHeight + 20);
+ this.mainContainer.SetFrameSize (new CGSize (this.mainContainer.Frame.Width, this.bindingPropertiesView.Hidden ? this.mainContainer.Frame.Height - MoreSettingsViewHeight : this.mainContainer.Frame.Height + MoreSettingsViewHeight));
+ SetFrame (new CGRect (new CGPoint (Frame.X, Frame.Y), new CGSize (Frame.Width, this.mainContainer.Frame.Height + this.titleBarHeight)), false, true);
+ }
+ }
+
+
+ private void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowLongDescription)) {
+ this.longDescription.Hidden = !ViewModel.ShowLongDescription;
+ this.longDescription.StringValue = ViewModel.ShowLongDescription ? ViewModel.SelectedBindingSource.Description : string.Empty;
+ this.typeHeader.Hidden = ViewModel.ShowLongDescription;
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) {
+ if (ViewModel.ShowObjectSelector) {
+ this.typeHeader.Title = Properties.Resources.SelectObjectTitle;
+ }
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowTypeSelector)) {
+ this.typeSelectorControl.Hidden = !ViewModel.ShowTypeSelector;
+
+ if (ViewModel.ShowTypeSelector) {
+ this.typeHeader.Title = Properties.Resources.SelectTypeTitle;
+
+ if (ViewModel.ShowTypeSelector && ViewModel.TypeSelector != null) {
+ this.typeSelectorControl.ViewModel = ViewModel.TypeSelector;
+ }
+ }
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) {
+ if (ViewModel.ShowResourceSelector) {
+ this.typeHeader.Title = Properties.Resources.SelectResourceTitle;
+ }
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.SelectedValueConverter)) {
+ RepopulateValueConverterPopup ();
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.PropertyDisplay)) {
+ Title = ViewModel.PropertyDisplay;
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.CanCreateBinding)) {
+ this.buttonDone.Enabled = ViewModel.CanCreateBinding;
+ }
+ }
+
+
+ private void CreateMorePropertiesEditors (IHostResourceProvider hostResources)
+ {
+ var controlTop = 8;
+ int editorHeight;
+
+ foreach (PropertyViewModel vm in ViewModel.BindingProperties) {
+ IEditorView editor = this.editorSelector.GetEditor (hostResources, vm);
+
+ NSView nSView = new EditorContainer (hostResources, editor, false) {
+ Identifier = BindingPropertiesIdentifier,
+ Label = vm.Property.Name,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ ViewModel = vm,
+ };
+
+ this.bindingPropertiesView.AddSubview (nSView);
+
+ editorHeight = (int)editor.GetHeight (vm);
+ this.bindingPropertiesView.AddConstraints (new[] {
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Top, 1f, controlTop),
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Right, 1f, -9f),
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, editorHeight),
+ });
+
+ controlTop += editorHeight;
+ }
+
+ var boundsHeight = controlTop;
+
+ controlTop = 8;
+ foreach (PropertyViewModel vm in ViewModel.FlagsProperties) {
+
+ IEditorView editor = this.editorSelector.GetEditor (hostResources, vm);
+
+ NSView nSView = new EditorContainer (hostResources, editor, false) {
+ Identifier = FlagPropertiesIdentifier,
+ Label = vm.Property.Name,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ ViewModel = vm,
+ };
+
+ this.flagsPropertiesView.AddSubview (nSView);
+
+ editorHeight = (int)editor.GetHeight (vm);
+ this.flagsPropertiesView.AddConstraints (new[] {
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Top, 1f, controlTop),
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, editorHeight)
+ });
+
+ controlTop += editorHeight;
+ }
+
+ if (boundsHeight < controlTop)
+ boundsHeight = controlTop;
+
+ MoreSettingsViewHeight = boundsHeight + 8;
+ }
+
+ private void RepopulateValueConverterPopup ()
+ {
+ this.valueConverterPopup.RemoveAllItems ();
+ foreach (Resource item in ViewModel.ValueConverters.Value) {
+ this.valueConverterPopup.Menu.AddItem (new NSMenuItem (item.Name) {
+ RepresentedObject = new NSObjectFacade (item)
+ });
+ }
+ }
+
+ private void OnCreateValueConverterRequested (object sender, CreateValueConverterEventArgs e)
+ {
+ ITypeInfo valueConverter = ViewModel.TargetPlatform.EditorProvider.KnownTypes[typeof (CommonValueConverter)];
+
+ var typesTask = ViewModel.TargetPlatform.EditorProvider.GetAssignableTypesAsync (valueConverter, childTypes: false)
+ .ContinueWith (t => t.Result.GetTypeTree (), TaskScheduler.Default);
+
+ var createValueConverterWindow = new CreateValueConverterWindow (ViewModel, new AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> (typesTask)) {
+ Appearance = EffectiveAppearance,
+ };
+
+ var result = (NSModalResponse)(int)NSApplication.SharedApplication.RunModalForWindow (createValueConverterWindow);
+ if (result == NSModalResponse.OK) {
+ if (createValueConverterWindow.ViewModel.SelectedType != null) {
+ e.Name = createValueConverterWindow.ValueConverterName;
+ e.ConverterType = createValueConverterWindow.ViewModel.SelectedType;
+ e.Source = createValueConverterWindow.ViewModel.Source;
+ }
+ }
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs
new file mode 100644
index 0000000..8e82477
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingObjectSelectorControl
+ : NotifyingView<CreateBindingViewModel>
+ {
+ private ObjectOutlineView objectOutlineView;
+
+ private const string ObjectSelectorColId = "ObjectSelectorColumn";
+
+ internal BindingObjectSelectorControl (CreateBindingViewModel viewModel)
+ {
+ if (viewModel == null)
+ throw new ArgumentNullException (nameof (viewModel));
+
+ ViewModel = viewModel;
+
+ this.objectOutlineView = new ObjectOutlineView ();
+ TranslatesAutoresizingMaskIntoConstraints = false;
+
+ this.objectOutlineView.Activated += OnObjectOutlineViewSelected;
+
+ var resourceColumn = new NSTableColumn (ObjectSelectorColId);
+ this.objectOutlineView.AddColumn (resourceColumn);
+
+ // Set OutlineTableColumn or the arrows showing children/expansion will not be drawn
+ this.objectOutlineView.OutlineTableColumn = resourceColumn;
+
+ // create a table view and a scroll view
+ var outlineViewContainer = new NSScrollView {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ // add the panel to the window
+ outlineViewContainer.DocumentView = this.objectOutlineView;
+ AddSubview (outlineViewContainer);
+
+ AddConstraints (new[] {
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 28f),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal,this, NSLayoutAttribute.Bottom, 1f, 0f),
+ });
+
+ viewModel.PropertyChanged += OnPropertyChanged;
+ }
+
+ public override void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) {
+ Hidden = !ViewModel.ShowObjectSelector;
+
+ if (ViewModel.ShowObjectSelector && ViewModel.ObjectElementRoots != null) {
+ this.objectOutlineView.ItemsSource = ViewModel.ObjectElementRoots.Value;
+ };
+ }
+ }
+
+ private void OnObjectOutlineViewSelected (object sender, EventArgs e)
+ {
+ if (sender is ObjectOutlineView rov) {
+ if (rov.SelectedRow != -1) {
+ if (rov.ItemAtRow (rov.SelectedRow) is NSObjectFacade item) {
+ if (item.Target is Resource resource) {
+ ViewModel.SelectedResource = resource;
+ }
+ }
+ }
+ }
+ }
+
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs
new file mode 100644
index 0000000..2d84be3
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using AppKit;
+using CoreGraphics;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingPathSelectorControl
+ : NotifyingView<CreateBindingViewModel>
+ {
+ private readonly PathOutlineView pathOutlineView;
+ internal const string PathSelectorColumnColId = "PathSelectorColumn";
+
+ public string CustomPath {
+ get {
+ return this.customPathControl.StringValue;
+ }
+ }
+ private NSTextField customPathControl { get; }
+
+ private const float HorizontalCustomOffSet = 30.5f;
+
+ private HeaderView pathHeader;
+ private NSView pathBox;
+
+ public BindingPathSelectorControl (CreateBindingViewModel viewModel)
+ {
+ if (viewModel == null)
+ throw new ArgumentNullException (nameof (viewModel));
+
+ ViewModel = viewModel;
+
+ TranslatesAutoresizingMaskIntoConstraints = false;
+
+ this.pathBox = new NSView {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ WantsLayer = true,
+
+ // Layer out of alphabetical order so that WantsLayer creates the layer first
+ Layer = {
+ CornerRadius = 1.0f,
+ BorderColor = new CGColor (.5f, .5f, .5f, 1.0f),
+ BorderWidth = 1,
+ },
+ };
+
+ AddSubview (this.pathBox);
+
+ this.pathHeader = new HeaderView {
+ Title = Properties.Resources.Path,
+ };
+ this.pathHeader.HorizonalTitleOffset = -HorizontalCustomOffSet;
+
+ this.pathBox.AddSubview (this.pathHeader);
+
+ this.pathBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, BindingEditorWindow.HeaderHeight),
+ });
+
+ var customCheckBox = new NSButton {
+ ControlSize = NSControlSize.Small,
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize),
+ Title = Properties.Resources.Custom,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ customCheckBox.SetButtonType (NSButtonType.Switch);
+
+ this.pathHeader.AddSubview (customCheckBox);
+ this.pathHeader.AddConstraints (new[] {
+ NSLayoutConstraint.Create (customCheckBox, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.pathHeader, NSLayoutAttribute.CenterX, 1, HorizontalCustomOffSet),
+ NSLayoutConstraint.Create (customCheckBox, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this.pathHeader, NSLayoutAttribute.CenterY, 1, 0f),
+ });
+
+ this.customPathControl = new NSTextField {
+ ControlSize = NSControlSize.Regular,
+ Enabled = false,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ var customPathHeightConstraint = NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 0);
+
+ this.pathBox.AddSubview (this.customPathControl);
+ this.pathBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Top, 1f, 28f),
+ NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.CenterX, 1, 0),
+ customPathHeightConstraint,
+ });
+
+ // create a table view and a scroll view
+ var outlineViewContainer = new NSScrollView {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ customCheckBox.Activated += (sender, e) => {
+ this.customPathControl.Enabled = customCheckBox.State == NSCellStateValue.On;
+ customPathHeightConstraint.Constant = this.customPathControl.Enabled ? 22 : 0;
+ };
+
+ this.customPathControl.Changed += (sender, e) => {
+ viewModel.Path = this.customPathControl.StringValue;
+ };
+
+ this.pathOutlineView = new PathOutlineView {
+
+ };
+
+ this.pathOutlineView.Activated += OnPathOutlineViewSelected;
+
+ var pathColumn = new NSTableColumn (PathSelectorColumnColId);
+ this.pathOutlineView.AddColumn (pathColumn);
+
+ // Set OutlineTableColumn or the arrows showing children/expansion will not be drawn
+ this.pathOutlineView.OutlineTableColumn = pathColumn;
+
+ // add the panel to the window
+ outlineViewContainer.DocumentView = this.pathOutlineView;
+
+ this.pathBox.AddSubview (outlineViewContainer);
+
+ this.pathBox.AddConstraints (new[] {
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.customPathControl, NSLayoutAttribute.Bottom, 1f, 0f),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.CenterX, 1, 0),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Bottom, 1f, 0f),
+ });
+
+ AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this, NSLayoutAttribute.Height, 1f, 0f),
+ NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, 0f),
+ });
+
+ viewModel.PropertyChanged += OnPropertyChanged;
+ }
+
+ public override async void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof (CreateBindingViewModel.PropertyRoot)) {
+ if (ViewModel.PropertyRoot != null) {
+ this.pathOutlineView.PropertyTreeRoot = await ViewModel.PropertyRoot.Task;
+ } else {
+ this.pathOutlineView.PropertyTreeRoot = null;
+ }
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.Path)) {
+ this.customPathControl.StringValue = ViewModel.Path ?? string.Empty;
+ }
+ }
+
+ private void OnPathOutlineViewSelected (object sender, EventArgs e)
+ {
+ if (sender is PathOutlineView pov) {
+ if (pov.SelectedRow != -1) {
+ if (pov.ItemAtRow (pov.SelectedRow) is NSObjectFacade facade) {
+ switch (facade.Target) {
+ case PropertyTreeElement propertyTreeElement:
+ ViewModel.SelectedPropertyElement = propertyTreeElement;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceOutlineView.cs
new file mode 100644
index 0000000..025fcba
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceOutlineView.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Linq;
+using AppKit;
+using Foundation;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingResourceOutlineView : BaseSelectorOutlineView
+ {
+ private ILookup<ResourceSource, Resource> itemsSource;
+ public ILookup<ResourceSource, Resource> ItemsSource
+ {
+ get => this.itemsSource;
+ set
+ {
+ if (this.itemsSource != value) {
+ this.itemsSource = value;
+
+ DataSource = new BindingResourceOutlineViewDataSource (this.itemsSource);
+ Delegate = new BindingResourceOutlineViewDelegate ();
+ }
+
+ ReloadData ();
+
+ ExpandItem (null, true);
+ }
+ }
+ }
+
+ internal class BindingResourceOutlineViewDelegate : NSOutlineViewDelegate
+ {
+ private const string ResourceIdentifier = "resource";
+
+ public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
+ {
+ var labelContainer = (UnfocusableTextField)outlineView.MakeView (ResourceIdentifier, this);
+ if (labelContainer == null) {
+ labelContainer = new UnfocusableTextField {
+ Identifier = ResourceIdentifier,
+ };
+ }
+ var target = (item as NSObjectFacade).Target;
+
+ switch (target) {
+ case IGrouping<ResourceSource, Resource> kvp:
+ labelContainer.StringValue = kvp.Key.Name;
+ break;
+ case Resource resource:
+ labelContainer.StringValue = resource.Name;
+ break;
+ default:
+ labelContainer.StringValue = Properties.Resources.ResourceNotSupported;
+ break;
+ }
+
+ return labelContainer;
+ }
+
+ public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item)
+ {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case IGrouping<ResourceSource, Resource> kvp:
+ return false;
+ case Resource resource:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ internal class BindingResourceOutlineViewDataSource : NSOutlineViewDataSource
+ {
+ public ILookup<ResourceSource, Resource> ItemsSource { get; }
+
+ internal BindingResourceOutlineViewDataSource (ILookup<ResourceSource, Resource> itemsSource)
+ {
+ if (itemsSource == null)
+ throw new ArgumentNullException (nameof (itemsSource));
+
+ ItemsSource = itemsSource;
+ }
+
+ public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item)
+ {
+ if (item == null) {
+ return ItemsSource != null ? ItemsSource.Count : 0;
+ } else {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case IGrouping<ResourceSource, Resource> kvp:
+ return kvp.Count ();
+ case Resource resource:
+ return 0;
+ default:
+ return 0;
+ }
+ }
+ }
+
+ public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item)
+ {
+ object element;
+
+ if (item == null) {
+ element = ItemsSource.ElementAt ((int)childIndex);
+ } else {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case IGrouping<ResourceSource, Resource> kvp:
+ element = kvp.ElementAt ((int)childIndex);
+ break;
+ case Resource resource:
+ element = resource;
+ break;
+ default:
+ return null;
+ }
+ }
+
+ return new NSObjectFacade (element);
+ }
+
+ public override bool ItemExpandable (NSOutlineView outlineView, NSObject item)
+ {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case IGrouping<ResourceSource, Resource> kvp:
+ return kvp.Any ();
+ case Resource resource:
+ return false;
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs
new file mode 100644
index 0000000..54a5e4b
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingResourceSelectorControl
+ : NotifyingView<CreateBindingViewModel>
+ {
+ private const string ResourceSelectorColId = "ResourceSelectorColumn";
+
+ public BindingResourceOutlineView resourceOutlineView;
+
+ internal BindingResourceSelectorControl (CreateBindingViewModel viewModel)
+ {
+ if (viewModel == null)
+ throw new ArgumentNullException (nameof (viewModel));
+
+ ViewModel = viewModel;
+
+ TranslatesAutoresizingMaskIntoConstraints = false;
+
+ this.resourceOutlineView = new BindingResourceOutlineView ();
+ this.resourceOutlineView.Activated += OnResourceOutlineViewSelected;
+
+ var resourceColumn = new NSTableColumn (ResourceSelectorColId);
+ this.resourceOutlineView.AddColumn (resourceColumn);
+
+ // Set OutlineTableColumn or the arrows showing children/expansion will not be drawn
+ this.resourceOutlineView.OutlineTableColumn = resourceColumn;
+
+ // create a table view and a scroll view
+ var outlineViewContainer = new NSScrollView {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ // add the panel to the window
+ outlineViewContainer.DocumentView = this.resourceOutlineView;
+ AddSubview (outlineViewContainer);
+
+ AddConstraints (new[] {
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 28f),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0),
+ NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal,this, NSLayoutAttribute.Bottom, 1f, 0f),
+ });
+
+ viewModel.PropertyChanged += OnPropertyChanged;
+ }
+
+ public override void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) {
+ Hidden = !ViewModel.ShowResourceSelector;
+
+ if (ViewModel.ShowResourceSelector && ViewModel.SourceResources != null) {
+ this.resourceOutlineView.ItemsSource = ViewModel.SourceResources.Value;
+ };
+ }
+ }
+
+ private void OnResourceOutlineViewSelected (object sender, EventArgs e)
+ {
+ if (sender is BindingResourceOutlineView rov) {
+ if (rov.SelectedRow != -1) {
+ if (rov.ItemAtRow (rov.SelectedRow) is NSObjectFacade item) {
+ if (item.Target is Resource resource) {
+ ViewModel.SelectedResource = resource;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs
new file mode 100644
index 0000000..b8c5c0e
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AppKit;
+using CoreGraphics;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class CreateValueConverterWindow : NSPanel
+ {
+ private new ModalWindowCloseDelegate Delegate {
+ get => (ModalWindowCloseDelegate)base.Delegate;
+ set => base.Delegate = value;
+ }
+
+ public AddValueConverterViewModel ViewModel { get; }
+
+ private NSTextField valueConverterName;
+ public string ValueConverterName {
+ get { return this.valueConverterName.Cell.Title; }
+ }
+
+ public CreateValueConverterWindow (CreateBindingViewModel viewModel, AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> typetasks)
+ {
+ if (viewModel == null)
+ throw new ArgumentNullException (nameof (viewModel));
+
+ Delegate = new ModalWindowCloseDelegate ();
+ ViewModel = new AddValueConverterViewModel (viewModel.TargetPlatform, viewModel.Target, typetasks);
+
+ StyleMask |= NSWindowStyle.Resizable;
+
+ Title = Properties.Resources.AddValueConverterTitle;
+
+ MaxSize = new CGSize (500, 560); // TODO discuss what the Max/Min Size should be and if we should have one.
+ MinSize = new CGSize (200, 320);
+
+ var container = new NSView (new CGRect (CGPoint.Empty, new CGSize (400, 400))) {
+ TranslatesAutoresizingMaskIntoConstraints = false
+ };
+
+ var valueConverterLabel = new UnfocusableTextField {
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13),
+ StringValue = Properties.Resources.ValueConverterName + ":",
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+ container.AddSubview (valueConverterLabel);
+
+ container.AddConstraints (new[] {
+ NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, container, NSLayoutAttribute.Top, 1f, 18f),
+ NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, container, NSLayoutAttribute.Left, 1f, 21f),
+ NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20),
+ });
+
+ this.valueConverterName = new NSTextField {
+ ControlSize = NSControlSize.Regular,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+ container.AddSubview (this.valueConverterName);
+
+ container.AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Top, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Bottom, 1f, 1f),
+ NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Left, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Width, NSLayoutRelation.Equal, container, NSLayoutAttribute.Width, 1f, -40f),
+ });
+
+ var typeSelectorControl = new TypeSelectorControl {
+ Flush = true,
+ ViewModel = ViewModel,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ container.AddSubview (typeSelectorControl);
+
+ container.AddConstraints (new[] {
+ NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.valueConverterName, NSLayoutAttribute.Bottom, 1f, 8f),
+ NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Left, 1f, 0f),
+ NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.valueConverterName, NSLayoutAttribute.Width, 1f, 0f),
+ NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, container, NSLayoutAttribute.Height, 1f, -95f),
+ });
+
+ var buttonSelect = new NSButton {
+ BezelStyle = NSBezelStyle.Rounded,
+ ControlSize = NSControlSize.Regular,
+ Enabled = false,
+ Highlighted = true,
+ KeyEquivalent = "\r", // Fire when enter pressed
+ Title = Properties.Resources.Select,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ buttonSelect.Activated += (sender, e) => {
+ Delegate.Response = NSModalResponse.OK;
+ Close ();
+ };
+
+ container.AddSubview (buttonSelect);
+
+ container.AddConstraints (new[] {
+ NSLayoutConstraint.Create (buttonSelect, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, container, NSLayoutAttribute.Bottom, 1f, -20f),
+ NSLayoutConstraint.Create (buttonSelect, NSLayoutAttribute.Right, NSLayoutRelation.Equal, typeSelectorControl, NSLayoutAttribute.Right, 1f, 0f),
+ NSLayoutConstraint.Create (buttonSelect, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f),
+ });
+
+ var buttonCancel = new NSButton {
+ BezelStyle = NSBezelStyle.Rounded,
+ ControlSize = NSControlSize.Regular,
+ Title = Properties.Resources.Cancel,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ buttonCancel.Activated += (sender, e) => {
+ Delegate.Response = NSModalResponse.Cancel;
+ Close ();
+ };
+
+ container.AddSubview (buttonCancel);
+
+ container.AddConstraints (new[] {
+ NSLayoutConstraint.Create (buttonCancel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, buttonSelect, NSLayoutAttribute.Top, 1f, 0f),
+ NSLayoutConstraint.Create (buttonCancel, NSLayoutAttribute.Right, NSLayoutRelation.Equal, buttonSelect, NSLayoutAttribute.Left, 1f, -10f),
+ NSLayoutConstraint.Create (buttonCancel, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f),
+ });
+
+ ContentViewController = new NSViewController (null, null) {
+ View = container,
+ };
+
+ ViewModel.PropertyChanged += (sender, e) => {
+ if (e.PropertyName == nameof (AddValueConverterViewModel.SelectedType)) {
+ this.valueConverterName.StringValue = ViewModel.SelectedType != null ? ViewModel.SelectedType.Name : string.Empty;
+ buttonSelect.Enabled = ViewModel.SelectedType != null;
+ }
+ };
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs
new file mode 100644
index 0000000..833a76b
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs
@@ -0,0 +1,47 @@
+using System;
+using AppKit;
+using CoreAnimation;
+using CoreGraphics;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class HeaderView : NSView
+ {
+ public string Title {
+ get { return this.headerText.StringValue; }
+ set { this.headerText.StringValue = value; }
+ }
+
+ private NSLayoutConstraint horizonalHeaderTextAlignment;
+ public nfloat HorizonalTitleOffset {
+ get { return this.horizonalHeaderTextAlignment.Constant; }
+ set { this.horizonalHeaderTextAlignment.Constant = value; }
+ }
+
+ private UnfocusableTextField headerText = new UnfocusableTextField {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ internal HeaderView ()
+ {
+ TranslatesAutoresizingMaskIntoConstraints = false;
+ WantsLayer = true;
+
+ // Layer out of alphabetical order so that WantsLayer creates the layer first
+ Layer = new CALayer {
+ CornerRadius = 1.0f,
+ BorderColor = new CGColor (.5f, .5f, .5f, 1.0f),
+ BorderWidth = 1,
+ };
+
+ this.horizonalHeaderTextAlignment = NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0);
+
+ AddSubview (this.headerText);
+ AddConstraints (new[] {
+ NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this, NSLayoutAttribute.Height, 1f, 0f),
+ this.horizonalHeaderTextAlignment,
+ NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterY, 1, 0f),
+ });
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/ObjectOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/ObjectOutlineView.cs
new file mode 100644
index 0000000..18ee0cf
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/ObjectOutlineView.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class ObjectOutlineView : BaseSelectorOutlineView
+ {
+ private IReadOnlyList<ObjectTreeElement> itemsSource;
+ public IReadOnlyList<ObjectTreeElement> ItemsSource
+ {
+ get => this.itemsSource;
+ set
+ {
+ if (this.itemsSource != value) {
+ this.itemsSource = value;
+
+ DataSource = new ObjectOutlineViewDataSource (this.itemsSource); ;
+ Delegate = new ObjectOutlineViewDelegate ();
+ }
+
+ ReloadData ();
+
+ ExpandItem (null, true);
+ }
+ }
+ }
+
+ internal class ObjectOutlineViewDelegate : NSOutlineViewDelegate
+ {
+ private const string TypeIdentifier = "type";
+
+ public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
+ {
+ var labelContainer = (UnfocusableTextField)outlineView.MakeView (TypeIdentifier, this);
+ if (labelContainer == null) {
+ labelContainer = new UnfocusableTextField {
+ Identifier = TypeIdentifier,
+ };
+ }
+ var target = (item as NSObjectFacade).Target;
+
+ switch (target) {
+ case KeyValuePair<string, SimpleCollectionView> kvp:
+ labelContainer.StringValue = kvp.Key;
+ break;
+ case TypeInfo info:
+ labelContainer.StringValue = info.Name;
+ break;
+ default:
+ labelContainer.StringValue = Properties.Resources.TypeNotSupported;
+ break;
+ }
+
+ return labelContainer;
+ }
+
+ public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item)
+ {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case KeyValuePair<string, SimpleCollectionView> kvp:
+ return false;
+ case TypeInfo info:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ internal class ObjectOutlineViewDataSource : NSOutlineViewDataSource
+ {
+ public IReadOnlyList<ObjectTreeElement> ItemsSource { get; }
+
+ internal ObjectOutlineViewDataSource (IReadOnlyList<ObjectTreeElement> itemsSource)
+ {
+ if (itemsSource == null)
+ throw new ArgumentNullException (nameof (itemsSource));
+
+ ItemsSource = itemsSource;
+ }
+
+ public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item)
+ {
+ if (item == null) {
+ return ItemsSource != null ? ItemsSource.Count : 0;
+ } else {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case KeyValuePair<string, SimpleCollectionView> kvp:
+ return kvp.Value.Count;
+ case TypeInfo info:
+ return 0;
+ default:
+ return 0;
+ }
+ }
+ }
+
+ public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item)
+ {
+ object element;
+
+ if (item == null) {
+ element = ItemsSource.ElementAt ((int)childIndex);
+ } else {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case KeyValuePair<string, SimpleCollectionView> kvp:
+ element = kvp.Value[(int)childIndex];
+ break;
+ case TypeInfo info:
+ element = info;
+ break;
+ default:
+ return null;
+ }
+ }
+
+ return new NSObjectFacade (element);
+ }
+
+ public override bool ItemExpandable (NSOutlineView outlineView, NSObject item)
+ {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case KeyValuePair<string, SimpleCollectionView> kvp:
+ return kvp.Value.Count > 0;
+ case TypeInfo info:
+ return false;
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/PathOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/PathOutlineView.cs
new file mode 100644
index 0000000..124cee6
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/PathOutlineView.cs
@@ -0,0 +1,168 @@
+using System;
+using System.Collections.Generic;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class PathOutlineView : BaseSelectorOutlineView
+ {
+ private IReadOnlyCollection<object> itemsSource;
+ private PropertyTreeRoot propertyTreeRoot;
+
+ private void SetItemsSource (IReadOnlyCollection<object> value, string targetName)
+ {
+ if (this.itemsSource != value) {
+ this.itemsSource = value;
+
+ DataSource = new PathOutlineViewDataSource (this.itemsSource, targetName); ;
+ Delegate = new PathOutlineViewDelegate ();
+
+ ReloadData ();
+
+ ExpandItem (ItemAtRow (0));
+ }
+ }
+
+ public PropertyTreeRoot PropertyTreeRoot
+ {
+ get { return this.propertyTreeRoot; }
+ internal set
+ {
+ if (this.propertyTreeRoot != value) {
+ this.propertyTreeRoot = value;
+ if (this.propertyTreeRoot != null) {
+ SetItemsSource (this.propertyTreeRoot.Children, this.propertyTreeRoot.TargetType.Name);
+ } else {
+ SetItemsSource (null, string.Empty);
+ }
+ }
+ }
+ }
+ }
+
+ internal class PathOutlineViewDelegate : NSOutlineViewDelegate
+ {
+ private const string PathIdentifier = "path";
+
+ public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
+ {
+ var labelContainer = (UnfocusableTextField)outlineView.MakeView (PathIdentifier, this);
+ if (labelContainer == null) {
+ labelContainer = new UnfocusableTextField {
+ Identifier = PathIdentifier,
+ };
+ }
+ var target = (item as NSObjectFacade).Target;
+
+ switch (target) {
+ case PropertyTreeElement propertyTreeElement:
+ labelContainer.StringValue = string.Format ("{0}: ({1})", propertyTreeElement.Property.Name, propertyTreeElement.Property.RealType.Name);
+ break;
+
+ case string targetName:
+ labelContainer.StringValue = targetName;
+ break;
+
+ default:
+ labelContainer.StringValue = Properties.Resources.TypeNotSupported;
+ break;
+ }
+
+ return labelContainer;
+ }
+
+ public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item)
+ {
+ if (item is NSObjectFacade facade) {
+ switch (facade.Target) {
+ case PropertyTreeElement propertyTreeElement:
+ var propertyTreeResult = propertyTreeElement.Children.Task.Result;
+ return propertyTreeResult.Count == 0;
+
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ internal class PathOutlineViewDataSource : NSOutlineViewDataSource
+ {
+ private readonly IReadOnlyCollection<object> itemsSource;
+ private readonly string targetName;
+
+ internal PathOutlineViewDataSource (IReadOnlyCollection<object> itemsSource, string targetName)
+ {
+ this.itemsSource = itemsSource;
+ this.targetName = targetName;
+ }
+
+ public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item)
+ {
+ if (item == null) {
+ return this.itemsSource != null ? this.itemsSource.Count + 1 : 0;
+ } else {
+ var target = (item as NSObjectFacade).Target;
+ switch (target) {
+ case PropertyTreeElement propertyTreeElement:
+ IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result;
+ return propertyTrees.Count;
+
+ case string targetName:
+ return this.itemsSource.Count;
+
+ default:
+ return 0;
+ }
+ }
+ }
+
+ public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item)
+ {
+ if (childIndex == 0 && item == null) {
+ return new NSObjectFacade (targetName);
+ }
+
+ if (item is NSObjectFacade objectFacade) {
+ var target = objectFacade.Target;
+ switch (target) {
+ case PropertyTreeElement propertyTreeElement:
+ IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result;
+ return new NSObjectFacade (propertyTrees.ElementAt ((int)childIndex));
+
+ case string targetName:
+ return new NSObjectFacade (this.itemsSource.ElementAt ((int)childIndex));
+
+ default:
+ return null;
+ }
+
+ }
+ return null;
+ }
+
+ public override bool ItemExpandable (NSOutlineView outlineView, NSObject item)
+ {
+ if (item is NSObjectFacade objectFacade) {
+ var target = objectFacade.Target;
+ switch (target) {
+ case PropertyTreeElement propertyTreeElement:
+ IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result;
+ return propertyTrees.Count > 0;
+
+ case string targetName:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs
index 4904bd8..4fde65f 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs
@@ -2,7 +2,7 @@ using System;
using System.Windows.Input;
using AppKit;
-namespace Xamarin.PropertyEditing.Mac.Controls.Custom
+namespace Xamarin.PropertyEditing.Mac
{
internal class CommandButton : NSButton
{
@@ -11,8 +11,7 @@ namespace Xamarin.PropertyEditing.Mac.Controls.Custom
public ICommand Command
{
get { return this.command; }
- set
- {
+ set {
if (this.command != null)
this.command.CanExecuteChanged -= CanExecuteChanged;
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
index 5768136..90ca577 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using AppKit;
using CoreGraphics;
using Xamarin.PropertyEditing.ViewModels;
@@ -19,12 +20,16 @@ namespace Xamarin.PropertyEditing.Mac
set {
if (this.viewModel != null) {
this.viewModel.PropertyChanged -= OnPropertyChanged;
+ if (this.viewModel.SupportsBindings)
+ this.viewModel.CreateBindingRequested -= OnBindingRequested;
}
this.viewModel = value;
if (this.viewModel != null) {
this.viewModel.PropertyChanged += OnPropertyChanged;
+ if (this.viewModel.SupportsBindings)
+ this.viewModel.CreateBindingRequested += OnBindingRequested;
ValueSourceChanged (this.viewModel.ValueSource);
}
@@ -113,10 +118,22 @@ namespace Xamarin.PropertyEditing.Mac
this.popUpContextMenu.AddItem (mi2);
}
+ if (this.viewModel.SupportsBindings) {
+ this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem);
+
+ this.popUpContextMenu.AddItem (new CommandMenuItem (Properties.Resources.CreateDataBindingMenuItem, this.viewModel.RequestCreateBindingCommand) {
+ AttributedTitle = new Foundation.NSAttributedString (
+ Properties.Resources.CreateDataBindingMenuItem,
+ new CoreText.CTStringAttributes {
+ Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1),
+ })
+ });
+ }
+
this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem);
// TODO If we add more menu items consider making the Label/Command a dictionary that we can iterate over to populate everything.
- this.popUpContextMenu.AddItem (new CommandMenuItem (Properties.Resources.Reset, viewModel.ClearValueCommand) {
+ this.popUpContextMenu.AddItem (new CommandMenuItem (Properties.Resources.Reset, this.viewModel.ClearValueCommand) {
AttributedTitle = new Foundation.NSAttributedString (
Properties.Resources.Reset,
new CoreText.CTStringAttributes {
@@ -242,5 +259,17 @@ namespace Xamarin.PropertyEditing.Mac
resourceSelectorPopOver.Show (requestResourceView.Frame, (NSView)this, NSRectEdge.MinYEdge);
}
+
+ private void OnBindingRequested (object sender, CreateBindingRequestedEventArgs e)
+ {
+ var bindingEditorWindow = new BindingEditorWindow (this.hostResources, this.viewModel) {
+ Appearance = EffectiveAppearance,
+ };
+
+ var result = (NSModalResponse)(int)NSApplication.SharedApplication.RunModalForWindow (bindingEditorWindow);
+ if (result == NSModalResponse.OK) {
+ e.BindingObject = bindingEditorWindow.ViewModel.SelectedObjects.Single ();
+ }
+ }
}
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs b/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs
index 2175b29..c22e438 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs
@@ -6,8 +6,8 @@ namespace Xamarin.PropertyEditing.Mac
internal class EditorContainer
: PropertyContainer
{
- public EditorContainer (IHostResourceProvider hostResources, IEditorView editorView)
- : base (hostResources, editorView, editorView?.NeedsPropertyButton ?? false)
+ public EditorContainer (IHostResourceProvider hostResources, IEditorView editorView, bool? needsPropertyButton = null)
+ : base (hostResources, editorView, needsPropertyButton ?? editorView?.NeedsPropertyButton ?? false)
{
}
@@ -22,7 +22,7 @@ namespace Xamarin.PropertyEditing.Mac
EditorView.ViewModel = value;
- if (EditorView.NeedsPropertyButton)
+ if (PropertyButton != null)
PropertyButton.ViewModel = value as PropertyViewModel;
}
}
@@ -57,8 +57,8 @@ namespace Xamarin.PropertyEditing.Mac
public override void ViewWillMoveToSuperview (NSView newSuperview)
{
- if (newSuperview == null && EditorView != null)
- EditorView.ViewModel = null;
+ if (newSuperview == null)
+ ViewModel = null;
base.ViewWillMoveToSuperview (newSuperview);
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
index 4b1e9b4..aff0ae5 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
@@ -75,23 +75,25 @@ namespace Xamarin.PropertyEditing.Mac
public void UpdateKeyViews ()
{
- nint row = TableView.RowForView (this);
- if (row <= 0)
- return;
-
- NSView view;
- PropertyEditorControl ctrl = null;
- do {
- row--;
- view = TableView.GetView (0, row, makeIfNecessary: false);
- ctrl = (view as EditorContainer)?.EditorView?.NativeView as PropertyEditorControl;
- } while (row > 0 && ctrl == null);
-
- if (ctrl != null) {
- ctrl.LastKeyView.NextKeyView = FirstKeyView;
- ctrl.UpdateKeyViews ();
- } else if (row == 0 && view is PanelHeaderEditorControl header) {
- header.SetNextKeyView (FirstKeyView);
+ if (TableView != null) {
+ nint row = TableView.RowForView (this);
+ if (row <= 0)
+ return;
+
+ NSView view;
+ PropertyEditorControl ctrl = null;
+ do {
+ row--;
+ view = TableView.GetView (0, row, makeIfNecessary: false);
+ ctrl = (view as EditorContainer)?.EditorView?.NativeView as PropertyEditorControl;
+ } while (row > 0 && ctrl == null);
+
+ if (ctrl != null) {
+ ctrl.LastKeyView.NextKeyView = FirstKeyView;
+ ctrl.UpdateKeyViews ();
+ } else if (row == 0 && view is PanelHeaderEditorControl header) {
+ header.SetNextKeyView (FirstKeyView);
+ }
}
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs
index 747ca64..d5574cb 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs
@@ -11,6 +11,25 @@ namespace Xamarin.PropertyEditing.Mac
internal class TypeSelectorControl
: NotifyingView<TypeSelectorViewModel>
{
+ private bool flush;
+ public bool Flush {
+ get { return this.flush; }
+ set {
+ this.flush = value;
+ this.filterTop.Constant = this.flush ? 0: 10;
+ this.filterWidth.Constant = this.flush ? 0 : -20;
+ this.scrollTop.Constant = this.flush ? 0 : 8;
+ this.checkBoxBottom.Constant = this.flush ? -28 : -10;
+ this.checkBoxLeft.Constant = this.flush ? 8 : 0;
+ }
+ }
+
+ private NSLayoutConstraint filterTop;
+ private NSLayoutConstraint filterWidth;
+ private NSLayoutConstraint scrollTop;
+ private NSLayoutConstraint checkBoxBottom;
+ private NSLayoutConstraint checkBoxLeft;
+
public TypeSelectorControl()
{
this.checkbox = NSButton.CreateCheckbox (Properties.Resources.ShowAllAssemblies, OnCheckedChanged);
@@ -36,7 +55,7 @@ namespace Xamarin.PropertyEditing.Mac
AddSubview (scroll);
- this.filter = new NSTextField {
+ this.filter = new NSSearchField {
TranslatesAutoresizingMaskIntoConstraints = false,
PlaceholderString = "Filter"
};
@@ -44,18 +63,24 @@ namespace Xamarin.PropertyEditing.Mac
AddSubview (this.filter);
+ this.filterTop = NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1, 10);
+ this.filterWidth = NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1, -20);
+ this.scrollTop = NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.filter, NSLayoutAttribute.Bottom, 1, 8);
+ this.checkBoxBottom = NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1, -10);
+ this.checkBoxLeft = NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, scroll, NSLayoutAttribute.Left, 1, 0);
+
AddConstraints (new[] {
- NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1, 10),
- NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1, -20),
+ this.filterTop,
+ this.filterWidth,
NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0),
- NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.filter, NSLayoutAttribute.Bottom, 1, 8),
+ this.scrollTop,
NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.filter, NSLayoutAttribute.Width, 1, 0),
NSLayoutConstraint.Create (scroll, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0),
NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.checkbox, NSLayoutAttribute.Top, 1, -8),
- NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1, -10),
- NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, scroll, NSLayoutAttribute.Left, 1, 0)
+ this.checkBoxBottom,
+ this.checkBoxLeft,
});
}
@@ -109,6 +134,8 @@ namespace Xamarin.PropertyEditing.Mac
for (int i = 0; i < this.outlineView.RowCount; i++) {
this.outlineView.ExpandItem (this.outlineView.ItemAtRow (i));
}
+ } else {
+ this.outlineView.ExpandItem (null, true);
}
}