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

ObjectPropertyViewModel.cs « ViewModels « Xamarin.PropertyEditing - github.com/xamarin/Xamarin.PropertyEditing.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f31b992acf436ac926884cf6d3b74b7c26b09228 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Xamarin.PropertyEditing.ViewModels
{
	internal class TypeRequestedEventArgs
		: EventArgs
	{
		/// <summary>
		/// Gets or sets a task for the type selected by the user from the UI
		/// </summary>
		public Task<ITypeInfo> SelectedType
		{
			get;
			set;
		}
	}

	internal class ObjectPropertyViewModel
		: PropertyViewModel<object>
	{
		public ObjectPropertyViewModel (TargetPlatform targetPlatform, IPropertyInfo property, IEnumerable<IObjectEditor> editors, PropertyVariation variation = null)
			: base (targetPlatform, property, editors, variation)
		{
			if (targetPlatform == null)
				throw new ArgumentNullException (nameof(targetPlatform));

			ValueModel = new ObjectViewModel (targetPlatform);
			RequestCurrentValueUpdate();
			CreateInstanceCommand = new RelayCommand (CreateInstance, () => IsAvailable && !IsCreateInstancePending);
		}

		public event EventHandler<TypeRequestedEventArgs> TypeRequested;

		public AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> AssignableTypes
		{
			get
			{
				if (this.assignableTypes == null)
					this.assignableTypes = new AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> (GetAssignableTypesAsync());

				return this.assignableTypes;
			}
		}

		public ICommand CreateInstanceCommand
		{
			get;
		}

		public override bool CanDelve
		{
			get { return this.canDelve; }
		}

		public ObjectViewModel ValueModel
		{
			get;
		}

		public ITypeInfo ValueType
		{
			get { return this.valueType; }
			private set
			{
				if (Equals (this.valueType, value))
					return;

				this.valueType = value;
				OnPropertyChanged();
			}
		}

		protected override void OnPropertyChanged ([CallerMemberName] string propertyName = null)
		{
			if (propertyName == nameof(IsAvailable)) {
				((RelayCommand)CreateInstanceCommand).ChangeCanExecute();
			}

			base.OnPropertyChanged (propertyName);
		}

		protected override async Task UpdateCurrentValueAsync ()
		{
			if (ValueModel == null)
				return;

			using (await AsyncWork.RequestAsyncWork (this)) {
				await base.UpdateCurrentValueAsync ();
				ValueType = CurrentValue?.ValueDescriptor as ITypeInfo;

				if (CurrentValue?.Value != null) {
					ValueModel.SelectedObjects.Reset (new[] { CurrentValue.Value });
				} else {
					ValueModel.SelectedObjects.Clear ();
				}

				SetCanDelve (ValueModel.SelectedObjects.Count > 0);
			}
		}

		private AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> assignableTypes;
		private bool createInstancePending;
		private ITypeInfo valueType;
		private bool canDelve;

		private bool IsCreateInstancePending
		{
			get { return this.createInstancePending; }
			set
			{
				if (this.createInstancePending == value)
					return;

				this.createInstancePending = value;
				((RelayCommand)CreateInstanceCommand).ChangeCanExecute();
			}
		}

		private void SetCanDelve (bool value)
		{
			if (this.canDelve == value)
				return;

			this.canDelve = value;
			OnPropertyChanged (nameof(CanDelve));
		}

		private async Task<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> GetAssignableTypesAsync ()
		{
			AssignableTypesResult result = await Editors.GetCommonAssignableTypes (Property, childTypes: false).ConfigureAwait (false);
			return result.GetTypeTree ();
		}

		private async void CreateInstance ()
		{
			IsCreateInstancePending = true;

			try {
				using (await AsyncWork.RequestAsyncWork (this)) {
					ITypeInfo selectedType = null;
				
					var types = await AssignableTypes.Task;
					// If there's only one assignable type, we'll skip selection
					if (types.Count == 1) {
						var kvp = types.First ();
						if (kvp.Value.Count == 1) {
							var group = kvp.Value.First ();
							if (!group.Skip (1).Any ()) {
								selectedType = group.First ();
							}
						}
					}

					if (selectedType == null) {
						var args = new TypeRequestedEventArgs ();
						TypeRequested?.Invoke (this, args);
						if (args.SelectedType == null)
							return;

						try {
							selectedType = await args.SelectedType;
 						} catch (OperationCanceledException) {
							return;
						}
					}

					await SetValueAsync (new ValueInfo<object> {
						Value = await TargetPlatform.EditorProvider.CreateObjectAsync (selectedType),
						ValueDescriptor = selectedType,
						Source = ValueSource.Local
					});
				}
			} finally {
				IsCreateInstancePending = false;
			}
		}
	}
}