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>2018-04-30 22:07:52 +0300
committerEric Maupin <ermaup@microsoft.com>2018-05-01 01:00:32 +0300
commit70c58f024cfb570d761105480126673db631ee5f (patch)
tree674526b7b9f8dd99b9bc341d4476a2d0aa0773d9 /Xamarin.PropertyEditing
parent31f4af0b1babf93cfad66617a84c1b85b8a3681b (diff)
[Core] Rework CollectionPropertyViewModel
In order to track rows for display purposes and in order to provide a clean way to get at the "real" name of the child, we've moved to using a VM per child. Since the main way to get a real name of an editable target is to request an object editor, we introduce a cached provider so the PanelViewModel doesn't have to get its own copy when the targets are selected. This collections tend to be small, but if we run into issues with the amount of things we're keeping alive we can easily move to on-demand requests.
Diffstat (limited to 'Xamarin.PropertyEditing')
-rw-r--r--Xamarin.PropertyEditing/TargetPlatform.cs14
-rw-r--r--Xamarin.PropertyEditing/ViewModels/CollectionPropertyViewModel.cs180
2 files changed, 181 insertions, 13 deletions
diff --git a/Xamarin.PropertyEditing/TargetPlatform.cs b/Xamarin.PropertyEditing/TargetPlatform.cs
index a7f00f2..6296149 100644
--- a/Xamarin.PropertyEditing/TargetPlatform.cs
+++ b/Xamarin.PropertyEditing/TargetPlatform.cs
@@ -67,5 +67,19 @@ namespace Xamarin.PropertyEditing
get;
set;
}
+
+ internal TargetPlatform WithProvider (IEditorProvider provider)
+ {
+ if (provider == null)
+ throw new ArgumentNullException (nameof(provider));
+
+ return new TargetPlatform (provider) {
+ SupportsMaterialDesign = SupportsMaterialDesign,
+ SupportsCustomExpressions = SupportsCustomExpressions,
+ SupportsBrushOpacity = SupportsBrushOpacity,
+ GroupedTypes = GroupedTypes,
+ AutoExpandGroups = AutoExpandGroups
+ };
+ }
}
}
diff --git a/Xamarin.PropertyEditing/ViewModels/CollectionPropertyViewModel.cs b/Xamarin.PropertyEditing/ViewModels/CollectionPropertyViewModel.cs
index 94f68a5..4c26ef2 100644
--- a/Xamarin.PropertyEditing/ViewModels/CollectionPropertyViewModel.cs
+++ b/Xamarin.PropertyEditing/ViewModels/CollectionPropertyViewModel.cs
@@ -9,15 +9,60 @@ using Xamarin.PropertyEditing.Properties;
namespace Xamarin.PropertyEditing.ViewModels
{
+ internal class CollectionPropertyItemViewModel
+ : NotifyingObject
+ {
+ public CollectionPropertyItemViewModel (object item, string typeName)
+ {
+ if (item == null)
+ throw new ArgumentNullException (nameof(item));
+ if (typeName == null)
+ throw new ArgumentNullException (nameof(typeName));
+
+ Item = item;
+ TypeName = typeName;
+ }
+
+ public object Item
+ {
+ get;
+ }
+
+ public string TypeName
+ {
+ get;
+ }
+
+ public int Row
+ {
+ get { return this.row; }
+ set
+ {
+ if (this.row == value)
+ return;
+
+ this.row = value;
+ OnPropertyChanged();
+ }
+ }
+
+ private int row;
+ }
+
+ // TODO: One thing this doesn't support currently is a way of previewing the changes
+
internal class CollectionPropertyViewModel
: PropertyViewModel<IList>
{
public CollectionPropertyViewModel (TargetPlatform platform, IPropertyInfo property, IEnumerable<IObjectEditor> editors)
: base (platform, property, editors)
{
+ if (this.cachedProvider == null)
+ this.cachedProvider = new CachedEditorProvider (platform.EditorProvider);
+
RequestTypes ();
- Panel = new PanelViewModel (platform) {
+ Panel = new PanelViewModel (platform.WithProvider (this.cachedProvider)) {
ArrangeMode = PropertyArrangeMode.Category,
AutoExpand = true
};
@@ -27,13 +72,14 @@ namespace Xamarin.PropertyEditing.ViewModels
MoveUpCommand = new RelayCommand (() => MoveTarget (up: true), () => CanMoveTarget (up: true));
MoveDownCommand = new RelayCommand (() => MoveTarget (up: false), () => CanMoveTarget (up: false));
CommitCommand = new RelayCommand (OnCommitCommand);
+ CancelCommand = new RelayCommand(RequestCurrentValueUpdate);
this.collectionView.CollectionChanged += OnCollectionViewContentsChanged;
}
public event EventHandler<TypeRequestedEventArgs> TypeRequested;
- public IReadOnlyList<object> Targets => this.collectionView;
+ public IReadOnlyList<CollectionPropertyItemViewModel> Targets => this.collectionView;
public IReadOnlyList<ITypeInfo> SuggestedTypes
{
@@ -61,7 +107,7 @@ namespace Xamarin.PropertyEditing.ViewModels
}
}
- public object SelectedTarget
+ public CollectionPropertyItemViewModel SelectedTarget
{
get { return this.selectedTarget; }
set
@@ -69,12 +115,15 @@ namespace Xamarin.PropertyEditing.ViewModels
if (this.selectedTarget == value)
return;
- object old = this.selectedTarget;
+ CollectionPropertyItemViewModel old = this.selectedTarget;
this.selectedTarget = value;
- if (value != null)
- Panel.SelectedObjects.ReplaceOrAdd (old, value);
- else
+ if (value != null) {
+ if (old == null)
+ Panel.SelectedObjects.Add (value.Item);
+ else
+ Panel.SelectedObjects.ReplaceOrAdd (old.Item, value.Item);
+ } else
Panel.SelectedObjects.Clear();
OnPropertyChanged();
@@ -128,12 +177,21 @@ namespace Xamarin.PropertyEditing.ViewModels
get;
}
+ public ICommand CancelCommand
+ {
+ get;
+ }
+
protected override async Task UpdateCurrentValueAsync ()
{
await base.UpdateCurrentValueAsync ();
+ if (this.cachedProvider == null)
+ this.cachedProvider = new CachedEditorProvider (TargetPlatform.EditorProvider);
+
+ this.cachedProvider.Clear();
if (Value != null)
- this.collectionView.Reset (Value.Cast<object>());
+ this.collectionView.Reset (await GetViewsFromValueAsync());
else
this.collectionView.Clear();
}
@@ -144,11 +202,70 @@ namespace Xamarin.PropertyEditing.ViewModels
RequestTypes ();
}
- private object selectedTarget;
+ // We need to grab the object editor for the children to get their "real" type name, but we don't want
+ // the panel view model to have query the editor again each time it's selected, so we'll give it this
+ // caching provider. Lists of this kind tend to be relatively small, but if becomes a problem we can
+ // add a window to the cache.
+
+ private class CachedEditorProvider
+ : IEditorProvider
+ {
+ public CachedEditorProvider (IEditorProvider realProvider)
+ {
+ if (realProvider == null)
+ throw new ArgumentNullException (nameof(realProvider));
+
+ this.realProvider = realProvider;
+ }
+
+ public void Add (IObjectEditor editor)
+ {
+ this.editors.Add (editor.Target, editor);
+ }
+
+ public void Remove (object target)
+ {
+ this.editors.Remove (target);
+ }
+
+ public void Clear ()
+ {
+ this.editors.Clear();
+ }
+
+ public Task<IObjectEditor> GetObjectEditorAsync (object item)
+ {
+ if (this.editors.TryGetValue (item, out IObjectEditor editor))
+ return Task.FromResult (editor);
+
+ return this.realProvider.GetObjectEditorAsync (item);
+ }
+
+ public async Task<IObjectEditor> GetAndCacheEditorAsync (object item)
+ {
+ if (!this.editors.TryGetValue (item, out IObjectEditor editor)) {
+ editor = await GetObjectEditorAsync (item);
+ this.editors[item] = editor;
+ }
+
+ return editor;
+ }
+
+ public Task<object> CreateObjectAsync (ITypeInfo type)
+ {
+ return this.realProvider.CreateObjectAsync (type);
+ }
+
+ private readonly Dictionary<object, IObjectEditor> editors = new Dictionary<object, IObjectEditor> ();
+ private readonly IEditorProvider realProvider;
+ }
+
+ private CollectionPropertyItemViewModel selectedTarget;
private ITypeInfo selectedType;
private AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> assignableTypes;
private ObservableCollectionEx<ITypeInfo> suggestedTypes;
- private readonly ObservableCollectionEx<object> collectionView = new ObservableCollectionEx<object> ();
+ private readonly ObservableCollectionEx<CollectionPropertyItemViewModel> collectionView = new ObservableCollectionEx<CollectionPropertyItemViewModel> ();
+ private CachedEditorProvider cachedProvider;
private static readonly ITypeInfo OtherType = new OtherTypeFake();
@@ -160,6 +277,20 @@ namespace Xamarin.PropertyEditing.ViewModels
public string Name => Resources.OtherTypeAction;
}
+ private async Task<IReadOnlyList<CollectionPropertyItemViewModel>> GetViewsFromValueAsync ()
+ {
+ var items = new List<CollectionPropertyItemViewModel> (Value.Count);
+ for (int i = 0; i < Value.Count; i++) {
+ object target = Value[i];
+ IObjectEditor editor = await this.cachedProvider.GetAndCacheEditorAsync (target);
+ items.Add (new CollectionPropertyItemViewModel (target, editor.TypeName) {
+ Row = i
+ });
+ }
+
+ return items;
+ }
+
private async void RequestTypes ()
{
if (Property == null)
@@ -180,7 +311,7 @@ namespace Xamarin.PropertyEditing.ViewModels
private Task PushValueAsync ()
{
- object[] snapshot = this.collectionView.ToArray ();
+ object[] snapshot = this.collectionView.Select (vm => vm.Item).ToArray ();
return SetValueAsync (new ValueInfo<IList> {
Value = snapshot,
Source = ValueSource.Local
@@ -229,24 +360,47 @@ namespace Xamarin.PropertyEditing.ViewModels
return (up) ? (index > 0) : (index < this.collectionView.Count - 1);
}
+ private void ReIndex ()
+ {
+ for (int i = 0; i < this.collectionView.Count; i++) {
+ this.collectionView[i].Row = i;
+ }
+ }
+
private void MoveTarget (bool up)
{
int index = this.collectionView.IndexOf (SelectedTarget);
this.collectionView.Move (index, index + ((up) ? -1 : 1));
+
+ ReIndex();
}
private async void OnAddTarget ()
{
object target = await TargetPlatform.EditorProvider.CreateObjectAsync (SelectedType);
- this.collectionView.Add (target);
- SelectedTarget = target;
+ IObjectEditor editor = await TargetPlatform.EditorProvider.GetObjectEditorAsync (target);
+ this.cachedProvider.Add (editor);
+
+ var vm = new CollectionPropertyItemViewModel (target, editor.TypeName);
+
+ if (SelectedTarget != null) {
+ this.collectionView.Insert (SelectedTarget.Row + 1, vm);
+ } else {
+ this.collectionView.Add (vm);
+ }
+
+ ReIndex();
+ SelectedTarget = vm;
}
private void OnRemoveTarget ()
{
int index = Math.Max (0, this.collectionView.IndexOf (SelectedTarget) - 1);
+ this.cachedProvider.Remove (SelectedTarget.Item);
this.collectionView.Remove (SelectedTarget);
+ ReIndex();
+
SelectedTarget = (this.collectionView.Count > 0) ? this.collectionView[index] : null;
}