From 72b0e3368581a5d0d081afcbe86ebd0a894b5d9f Mon Sep 17 00:00:00 2001 From: Eric Maupin Date: Tue, 19 Mar 2019 14:34:08 -0400 Subject: [Core] Ensure variants update correctly Additionally adds some extra tracking properties we'll need for the UI, HasVariantChildren / IsVariant control alt-background and presentation of remove variant controls. --- .../ViewModels/PropertiesViewModel.cs | 82 ++++++++++++++-------- .../ViewModels/PropertyViewModel.cs | 23 +++++- 2 files changed, 75 insertions(+), 30 deletions(-) (limited to 'Xamarin.PropertyEditing') diff --git a/Xamarin.PropertyEditing/ViewModels/PropertiesViewModel.cs b/Xamarin.PropertyEditing/ViewModels/PropertiesViewModel.cs index e97647b..9bf6bf1 100644 --- a/Xamarin.PropertyEditing/ViewModels/PropertiesViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/PropertiesViewModel.cs @@ -167,6 +167,7 @@ namespace Xamarin.PropertyEditing.ViewModels removedEditors = new IObjectEditor[e.OldItems.Count]; for (int i = 0; i < e.OldItems.Count; i++) { IObjectEditor editor = this.objEditors.First (oe => oe?.Target == e.OldItems[i]); + editor.PropertyChanged -= OnObjectEditorPropertyChanged; INotifyCollectionChanged notifier = editor.Properties as INotifyCollectionChanged; if (notifier != null) notifier.CollectionChanged -= OnObjectEditorPropertiesChanged; @@ -181,8 +182,13 @@ namespace Xamarin.PropertyEditing.ViewModels case NotifyCollectionChangedAction.Reset: { removedEditors = new IObjectEditor[this.objEditors.Count]; for (int i = 0; i < removedEditors.Length; i++) { - removedEditors[i] = this.objEditors[i]; - INotifyCollectionChanged notifier = removedEditors[i]?.Properties as INotifyCollectionChanged; + IObjectEditor editor = this.objEditors[i]; + if (editor == null) + continue; + + removedEditors[i] = editor; + editor.PropertyChanged -= OnObjectEditorPropertyChanged; + INotifyCollectionChanged notifier = editor.Properties as INotifyCollectionChanged; if (notifier != null) notifier.CollectionChanged -= OnObjectEditorPropertiesChanged; } @@ -226,20 +232,45 @@ namespace Xamarin.PropertyEditing.ViewModels ErrorsChanged?.Invoke (this, e); } + private void OnObjectEditorPropertyChanged (object sender, EditorPropertyChangedEventArgs e) + { + if (!e.Property.HasVariations ()) + return; + + OnVariationsChanged (e.Property, EventArgs.Empty); + } + private async void OnVariationsChanged (object sender, EventArgs e) { + IPropertyInfo property = sender as IPropertyInfo; + if (property == null) + property = ((PropertyViewModel)sender).Property; + using (await AsyncWork.RequestAsyncWork (this)) { - PropertyViewModel pvm = (PropertyViewModel) sender; - var variations = (await GetVariationsAsync (pvm.Property)).SelectMany (vs => vs).Distinct (); - var properties = this.editors - .OfType () - .Where (evm => Equals (evm.Property, pvm.Property) && evm.Variation != null) - .ToDictionary (evm => evm.Variation); + var variationsTask = GetVariationsAsync (property); + + PropertyViewModel baseVm = null; + var properties = new Dictionary (); + foreach (PropertyViewModel pvm in this.editors.OfType ()) { + if (!Equals (property, pvm.Property)) + continue; + + if (pvm.Variation == null) + baseVm = pvm; + else + properties.Add (pvm.Variation, pvm); + } + + if (baseVm == null) + throw new InvalidOperationException ("Base property view model couldn't be found"); + + var variations = await variationsTask; + baseVm.HasVariantChildren = variations.Count > 0; List toAdd = new List (); foreach (PropertyVariation variation in variations) { if (!properties.Remove (variation)) { - toAdd.Add (GetViewModel (pvm.Property, variation)); + toAdd.Add (CreateViewModel (property, variation)); } } @@ -472,12 +503,11 @@ namespace Xamarin.PropertyEditing.ViewModels List newVms = new List (); foreach (IPropertyInfo property in newSet) { if (variations != null && variations.TryGetValue (property, out Dictionary propertyVariations)) { - var setVariations = (await GetVariationsAsync (property)).SelectMany (vs => vs).Distinct (); - foreach (PropertyVariation variation in setVariations) { + foreach (PropertyVariation variation in await GetVariationsAsync (property)) { if (propertyVariations.Remove (variation)) continue; - newVms.Add (GetViewModel (property, variation)); + newVms.Add (CreateViewModel (property, variation)); } foreach (var kvp in propertyVariations) { @@ -486,7 +516,7 @@ namespace Xamarin.PropertyEditing.ViewModels } else if (property.HasVariations()) { newVms.AddRange (await GetViewModelsAsync (property)); } else { - newVms.Add (GetViewModel (property)); + newVms.Add (CreateViewModel (property)); } } @@ -511,6 +541,7 @@ namespace Xamarin.PropertyEditing.ViewModels if (editor == null) continue; + editor.PropertyChanged += OnObjectEditorPropertyChanged; var notifier = editor.Properties as INotifyCollectionChanged; if (notifier != null) notifier.CollectionChanged += OnObjectEditorPropertiesChanged; @@ -532,35 +563,28 @@ namespace Xamarin.PropertyEditing.ViewModels tcs.SetResult (true); } - private Task[]> GetVariationsAsync (IPropertyInfo property) + private async Task> GetVariationsAsync (IPropertyInfo property) { var variantTasks = new List>> (ObjectEditors.Count); for (int i = 0; i < ObjectEditors.Count; i++) { variantTasks.Add (ObjectEditors[i].GetPropertyVariantsAsync (property)); } - return Task.WhenAll (variantTasks); + return (await Task.WhenAll (variantTasks)).SelectMany (vs => vs).Distinct ().ToList (); } - private async Task> GetViewModelsAsync (IPropertyInfo property, IEnumerable variantsToSkip = null) + private async Task> GetViewModelsAsync (IPropertyInfo property) { - PropertyViewModel baseVm = GetViewModel (property); - List vms = new List (); - vms.Add (baseVm); - - HashSet skipped = - (variantsToSkip != null) ? new HashSet (variantsToSkip) : null; + PropertyViewModel baseVm = CreateViewModel (property); + var vms = new List { baseVm }; if (baseVm.HasVariations) { using (await AsyncWork.RequestAsyncWork (this)) { var variants = await GetVariationsAsync (property); - for (int i = 0; i < variants.Length; i++) { - foreach (PropertyVariation variant in variants[i]) { - if (skipped != null && skipped.Contains (variant)) - continue; + baseVm.HasVariantChildren = variants.Count > 0; - vms.Add (GetViewModel (property, variant)); - } + foreach (PropertyVariation variant in variants) { + vms.Add (CreateViewModel (property, variant)); } } } @@ -568,7 +592,7 @@ namespace Xamarin.PropertyEditing.ViewModels return vms; } - private PropertyViewModel GetViewModel (IPropertyInfo property, PropertyVariation variant = null) + private PropertyViewModel CreateViewModel (IPropertyInfo property, PropertyVariation variant = null) { PropertyViewModel vm; Type[] interfaces = property.GetType ().GetInterfaces (); diff --git a/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs b/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs index 951e848..2d6319b 100644 --- a/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/PropertyViewModel.cs @@ -516,7 +516,7 @@ namespace Xamarin.PropertyEditing.ViewModels private bool CanCreateVariation () { - return HasVariations; + return HasVariations && !IsVariant; } private async void OnCreateVariation () @@ -611,8 +611,26 @@ namespace Xamarin.PropertyEditing.ViewModels get { return Property.CanWrite && TargetPlatform.BindingProvider != null && Property.ValueSources.HasFlag (ValueSources.Binding); } } + /// + /// Gets whether the property has possible variations. + /// public bool HasVariations => Property.HasVariations(); + public bool HasVariantChildren + { + get { return this.hasVariantChildren; } + internal set + { + if (this.hasVariantChildren == value) + return; + + this.hasVariantChildren = value; + OnPropertyChanged(); + } + } + + public bool IsVariant => Variation != null; + public abstract Resource Resource { get; @@ -737,6 +755,8 @@ namespace Xamarin.PropertyEditing.ViewModels try { if (e.Property != null && !Equals (e.Property, Property)) return; + if (!Equals (Variation, e.Variation)) + return; // TODO: Smarter querying, can query the single editor and check against MultipleValues await UpdateCurrentValueAsync (); @@ -800,6 +820,7 @@ namespace Xamarin.PropertyEditing.ViewModels private HashSet constraintProperties; private string error; private Task isAvailable; + private bool hasVariantChildren; private void OnErrorsChanged (DataErrorsChangedEventArgs e) { -- cgit v1.2.3