diff options
author | Eric Maupin <ermaup@microsoft.com> | 2019-04-24 21:13:36 +0300 |
---|---|---|
committer | Eric Maupin <ermaup@microsoft.com> | 2019-04-24 21:13:36 +0300 |
commit | ad499d8c9312e7f1c211af8c89eac3cf4cb93018 (patch) | |
tree | 2be456d6d5b606c0e9c8b43e9eb60342b4c5b2c7 | |
parent | c004b45395ffd9c012ece8bd6b66f8f4f2c33f4f (diff) |
wip restoreermau-restore-binding
10 files changed, 150 insertions, 33 deletions
diff --git a/Xamarin.PropertyEditing.Tests/MockBindingProvider.cs b/Xamarin.PropertyEditing.Tests/MockBindingProvider.cs index 8077ed4..67c3e1c 100644 --- a/Xamarin.PropertyEditing.Tests/MockBindingProvider.cs +++ b/Xamarin.PropertyEditing.Tests/MockBindingProvider.cs @@ -61,7 +61,7 @@ namespace Xamarin.PropertyEditing.Tests private static readonly BindingSource StaticResource = new BindingSource ("StaticResource", BindingSourceType.Resource); private class BindingSourceInstance - : BindingSource + : BindingSource, IEquatable<BindingSourceInstance> { public BindingSourceInstance (BindingSource original, string description) : base (original.Name, original.Type, description) @@ -73,6 +73,41 @@ namespace Xamarin.PropertyEditing.Tests { get; } + + public override bool Equals (object obj) + { + if (ReferenceEquals (null, obj)) + return false; + if (ReferenceEquals (this, obj)) + return true; + if (obj.GetType () != GetType ()) + return false; + return Equals ((BindingSourceInstance) obj); + } + + public bool Equals (BindingSourceInstance other) + { + if (ReferenceEquals (null, other)) + return false; + if (ReferenceEquals (this, other)) + return true; + return Original.Equals (other.Original); + } + + public override int GetHashCode () + { + return Original.GetHashCode (); + } + + public static bool operator == (BindingSourceInstance left, BindingSourceInstance right) + { + return Equals (left, right); + } + + public static bool operator != (BindingSourceInstance left, BindingSourceInstance right) + { + return !Equals (left, right); + } } } diff --git a/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml b/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml index d233dc4..a6ce330 100644 --- a/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml +++ b/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml @@ -120,7 +120,7 @@ <local:TextBoxEx Grid.Row="3" Grid.Column="2" VerticalAlignment="Top" Margin="0,4,0,4" Visibility="{Binding ElementName=content,Path=IsChecked,Converter={StaticResource BoolToVisibilityConverter}}" Text="{Binding Path,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> <TextBlock Name="longDescription" Grid.Row="3" Grid.RowSpan="2" Grid.Column="0" VerticalAlignment="Stretch" Text="{Binding SelectedBindingSource.Description}" Visibility="{Binding ShowLongDescription,Converter={StaticResource BoolToVisibilityConverter}}" /> - <local:TreeViewEx Grid.Row="3" Grid.RowSpan="2" Grid.Column="0" Margin="0,4,0,0" Style="{DynamicResource SelectionTreeView}" ItemsSource="{Binding ObjectElementRoots.Value}" DisplayMemberPath="Name.Value" Visibility="{Binding ShowObjectSelector,Converter={StaticResource BoolToVisibilityConverter}}" /> + <local:TreeViewEx Grid.Row="3" Grid.RowSpan="2" Grid.Column="0" Margin="0,4,0,0" Style="{DynamicResource SelectionTreeView}" ItemsSource="{Binding ObjectElementRoots.Value}" DisplayMemberPath="Name.Value" Visibility="{Binding ShowObjectSelector,Converter={StaticResource BoolToVisibilityConverter}}" SelectedDataItem="{Binding SelectedObjectTreeElement,Mode=TwoWay}" /> <local:TreeViewEx Grid.Row="3" Grid.RowSpan="2" Grid.Column="0" Margin="0,4,0,0" Style="{DynamicResource AutoExpandSelectionTreeView}" ItemsSource="{Binding SourceResources.Value}" Visibility="{Binding ShowResourceSelector,Converter={StaticResource BoolToVisibilityConverter}}" SelectedDataItem="{Binding SelectedResource,Mode=TwoWay}"> <local:TreeViewEx.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Mode=OneTime}"> @@ -133,10 +133,10 @@ </HierarchicalDataTemplate> </local:TreeViewEx.ItemTemplate> </local:TreeViewEx> - <local:TypeSelectorControl Grid.Row="3" Grid.RowSpan="2" Grid.Column="0" Margin="0,4,0,0" Visibility="{Binding DataContext.ShowTypeSelector,Converter={StaticResource BoolToVisibilityConverter},ElementName=propertiesTree}" ShowTypeLevel="{Binding DataContext.ShowTypeLevel,ElementName=propertiesTree}" DataContext="{Binding TypeSelector}" TypeLevel="{Binding TypeLevel,Mode=TwoWay}" /> + <local:TypeSelectorControl Grid.Row="3" Grid.RowSpan="2" Grid.Column="0" Margin="0,4,0,0" Visibility="{Binding DataContext.ShowTypeSelector,Converter={StaticResource BoolToVisibilityConverter},ElementName=propertiesTree}" ShowTypeLevel="{Binding DataContext.ShowTypeLevel,ElementName=propertiesTree}" DataContext="{Binding TypeSelector}" TypeLevel="{Binding TypeLevel,Mode=TwoWay}" /> <local:TreeViewEx x:Name="propertiesTree" Grid.Row="4" Grid.Column="2" Margin="0,4,0,0" Style="{DynamicResource SelectionTreeView}" SelectedDataItem="{Binding SelectedPropertyElement,Mode=TwoWay}"> - <local:TreeViewItemEx Header="{Binding PropertyRoot.Value.TargetType.Name}" IsExpanded="True" ItemsSource="{Binding PropertyRoot.Value.Children}" ItemContainerStyle="{DynamicResource SelectionTreeViewItem}"> + <local:TreeViewItemEx DataContext="{Binding PropertyRoot.Value}" Header="{Binding TargetType.Name}" IsExpanded="True" ItemsSource="{Binding Children}" ItemContainerStyle="{DynamicResource SelectionTreeViewItem}"> <local:TreeViewItemEx.ItemTemplate> <HierarchicalDataTemplate DataType="vms:PropertyTreeElement" ItemsSource="{Binding Children.Value}"> <TextBlock> diff --git a/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml.cs b/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml.cs index 72ea59d..f60630b 100644 --- a/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml.cs +++ b/Xamarin.PropertyEditing.Windows/CreateBindingWindow.xaml.cs @@ -12,9 +12,9 @@ namespace Xamarin.PropertyEditing.Windows internal partial class CreateBindingWindow : WindowEx { - public CreateBindingWindow (IEnumerable<ResourceDictionary> merged, TargetPlatform platform, IObjectEditor editor, IPropertyInfo property) + public CreateBindingWindow (IEnumerable<ResourceDictionary> merged, TargetPlatform platform, IObjectEditor editor, IPropertyInfo property, PropertyVariation variation = null, object bindingObject = null) { - var vm = new CreateBindingViewModel (platform, editor, property); + var vm = new CreateBindingViewModel (platform, editor, property, variation, bindingObject); vm.CreateValueConverterRequested += OnCreateValueConverterRequested; DataContext = vm; @@ -49,10 +49,10 @@ namespace Xamarin.PropertyEditing.Windows DialogResult = false; } - internal static object CreateBinding (FrameworkElement owner, TargetPlatform platform, IObjectEditor editor, IPropertyInfo property) + internal static object CreateBinding (FrameworkElement owner, TargetPlatform platform, IObjectEditor editor, IPropertyInfo property, PropertyVariation variation = null, object bindingObject = null) { Window ownerWindow = Window.GetWindow (owner); - var window = new CreateBindingWindow (owner.Resources.MergedDictionaries, platform, editor, property) { + var window = new CreateBindingWindow (owner.Resources.MergedDictionaries, platform, editor, property, variation, bindingObject) { Owner = ownerWindow }; bool? result = window.ShowDialog (); diff --git a/Xamarin.PropertyEditing.Windows/PropertyButton.cs b/Xamarin.PropertyEditing.Windows/PropertyButton.cs index 89434de..bf5ecb1 100644 --- a/Xamarin.PropertyEditing.Windows/PropertyButton.cs +++ b/Xamarin.PropertyEditing.Windows/PropertyButton.cs @@ -162,7 +162,7 @@ namespace Xamarin.PropertyEditing.Windows var panel = this.FindPropertiesHost (); var pvm = (PropertyViewModel) DataContext; - e.BindingObject = CreateBindingWindow.CreateBinding (panel, pvm.TargetPlatform, pvm.Editors.Single(), pvm.Property); + e.BindingObject = CreateBindingWindow.CreateBinding (panel, pvm.TargetPlatform, pvm.Editors.Single(), pvm.Property, pvm.Variation, e.BindingObject); } private void OnResourceRequested (object sender, ResourceRequestedEventArgs e) diff --git a/Xamarin.PropertyEditing.Windows/TreeViewItemEx.cs b/Xamarin.PropertyEditing.Windows/TreeViewItemEx.cs index ef40e26..554979d 100644 --- a/Xamarin.PropertyEditing.Windows/TreeViewItemEx.cs +++ b/Xamarin.PropertyEditing.Windows/TreeViewItemEx.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Reflection; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; @@ -74,10 +75,29 @@ namespace Xamarin.PropertyEditing.Windows value.IsSelected = true; } - SetSelectedItem (oldItem, value?.DataContext); - this.fromTreeItem = true; - SetCurrentValue (SelectedDataItemProperty, value?.DataContext); - this.fromTreeItem = false; + void SetItem (object old, object newItem) + { + SetSelectedItem (old, newItem); + this.fromTreeItem = true; + SetCurrentValue (SelectedDataItemProperty, newItem); + this.fromTreeItem = false; + } // doesn't work + + if (value != null && !value.IsDescendantOf (this)) { + RoutedEventHandler loaded = null; + loaded = (sender, args) => { + if (this.selectedTreeItem == value) { + SetItem (oldItem, value.DataContext); + } + + value.Loaded -= loaded; + }; + + value.Loaded += loaded; + return; + } + + SetItem (oldItem, value?.DataContext); } } @@ -95,6 +115,19 @@ namespace Xamarin.PropertyEditing.Windows return; } + if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) { + EventHandler statusHandler = null; + statusHandler = (sender, args) => { + if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { + ItemContainerGenerator.StatusChanged -= statusHandler; + OnSelectedDataItemChanged(); + } + }; + + ItemContainerGenerator.StatusChanged += statusHandler; + return; + } + TreeViewItemEx treeItem = FindItem (ItemContainerGenerator, item); if (treeItem == null) return; @@ -109,17 +142,17 @@ namespace Xamarin.PropertyEditing.Windows var path = pathProvider.GetItemParents (item); for (int i = 0; i < path.Count; i++) { - if (ItemsSource != null) { - treeItem = (TreeViewItemEx) generator.ContainerFromItem (path[i]); - } else { // Manual items won't map, despite data contexts - for (int x = 0; x < generator.Items.Count; x++) { - if (!(generator.Items[x] is TreeViewItemEx tvi)) - continue; - - if (Equals (tvi.DataContext, path[i])) { - treeItem = tvi; - break; - } + for (int x = 0; x < generator.Items.Count; x++) { + object context = null; + object genItem = generator.Items[x]; + if (genItem is FrameworkElement fe) { + context = fe.DataContext; + } else + context = genItem; + + if (Equals (context, path[i])) { + treeItem = (TreeViewItemEx)generator.GetOrCreateContainerFromIndex (x); + break; } } @@ -129,6 +162,8 @@ namespace Xamarin.PropertyEditing.Windows treeItem.IsExpanded = true; generator = treeItem.ItemContainerGenerator; } + + return treeItem; } // This is a fallback that will fail if virtualized away @@ -256,6 +291,9 @@ namespace Xamarin.PropertyEditing.Windows protected override void OnSelected (RoutedEventArgs e) { TreeViewEx parent = GetParentTree(); + if (parent == null) + return; + if (!IsSelectable) { IsSelected = false; e.Handled = true; diff --git a/Xamarin.PropertyEditing.Windows/XamlHelper.cs b/Xamarin.PropertyEditing.Windows/XamlHelper.cs index 7f3ac32..b943b80 100644 --- a/Xamarin.PropertyEditing.Windows/XamlHelper.cs +++ b/Xamarin.PropertyEditing.Windows/XamlHelper.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Media; namespace Xamarin.PropertyEditing.Windows @@ -74,5 +76,19 @@ namespace Xamarin.PropertyEditing.Windows return (TParent)parent; } + + public static DependencyObject GetOrCreateContainerFromIndex (this ItemContainerGenerator self, int index) + { + DependencyObject treeItem = self.ContainerFromIndex (index); + if (treeItem == null && self.Status != GeneratorStatus.ContainersGenerated) { + IItemContainerGenerator igen = self; + GeneratorPosition pos = igen.GeneratorPositionFromIndex (index); + using (igen.StartAt (pos, GeneratorDirection.Forward)) { + treeItem = igen.GenerateNext (); + } + } + + return treeItem; + } } } diff --git a/Xamarin.PropertyEditing/ViewModels/CreateBindingViewModel.cs b/Xamarin.PropertyEditing/ViewModels/CreateBindingViewModel.cs index 63cd5a1..5b199be 100644 --- a/Xamarin.PropertyEditing/ViewModels/CreateBindingViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/CreateBindingViewModel.cs @@ -727,19 +727,36 @@ namespace Xamarin.PropertyEditing.ViewModels IReadOnlyList<object> IProvidePath.GetItemParents (object item) { + List<object> path = new List<object> (); + switch (item) { case PropertyTreeElement prop: - List<object> path = new List<object> (); - var current = prop; - while (current != null) { - path.Insert (0, current); - current = current.Parent; + var currentProp = prop; + while (currentProp != null) { + path.Insert (0, currentProp); + currentProp = currentProp.Parent; } path.Insert (0, PropertyRoot.Value); return path; + case ObjectTreeElement obj: + var currentObj = obj; + while (currentObj != null) { + path.Insert (0, currentObj); + currentObj = currentObj.Parent; + } + + return path; case Resource resource: - return new object[] { resource.Source, resource }; + foreach (var k in SourceResources.Value) { + if (k.Key == resource.Source) { + path.Add (k); + break; + } + } + + path.Add (resource); + return path; default: throw new ArgumentException(); } diff --git a/Xamarin.PropertyEditing/ViewModels/EventViewModel.cs b/Xamarin.PropertyEditing/ViewModels/EventViewModel.cs index a50eb5f..a233cf8 100644 --- a/Xamarin.PropertyEditing/ViewModels/EventViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/EventViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/Xamarin.PropertyEditing/ViewModels/ObjectTreeElement.cs b/Xamarin.PropertyEditing/ViewModels/ObjectTreeElement.cs index 5064ef3..56f22f5 100644 --- a/Xamarin.PropertyEditing/ViewModels/ObjectTreeElement.cs +++ b/Xamarin.PropertyEditing/ViewModels/ObjectTreeElement.cs @@ -31,6 +31,12 @@ namespace Xamarin.PropertyEditing.ViewModels Name = new AsyncValue<string> (nameTask, typeName); } + private ObjectTreeElement (IEditorProvider provider, IObjectEditor editor, ObjectTreeElement parent) + : this (provider, editor) + { + Parent = parent; + } + public AsyncValue<string> Name { get; @@ -41,6 +47,11 @@ namespace Xamarin.PropertyEditing.ViewModels get; } + public ObjectTreeElement Parent + { + get; + } + public AsyncValue<IReadOnlyList<ObjectTreeElement>> Children { get; @@ -56,7 +67,7 @@ namespace Xamarin.PropertyEditing.ViewModels } IObjectEditor[] editors = await Task.WhenAll (editorTasks); - return editors.Select (e => new ObjectTreeElement (provider, e)).ToArray (); + return editors.Select (e => new ObjectTreeElement (provider, e, this)).ToArray (); } } }
\ No newline at end of file diff --git a/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs b/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs index 407dbe1..7555fad 100644 --- a/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs @@ -50,7 +50,7 @@ namespace Xamarin.PropertyEditing.ViewModels public override ValueSource ValueSource => this.value != null ? this.value.Source : ValueSource.Default; /// <remarks> - /// This is only meant for use from the UI. Other value setting mechanisms (like, converting resources to local, or setting to a resource) should + /// The setter is only meant for use from the UI. Other value setting mechanisms (like, converting resources to local, or setting to a resource) should /// use bespoke value setting mechanisms as this property switches the value source to local and only if the value itself has changed. /// </remarks> public TValue Value |