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

IObjectEditor.cs « Xamarin.PropertyEditing - github.com/xamarin/Xamarin.PropertyEditing.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 03f908137abae695bb25007f28ce3ce41063dd3f (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
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Xamarin.PropertyEditing
{
	public class EditorPropertyChangedEventArgs
		: EventArgs
	{
		/// <param name="property">The property that was updated, or <c>null</c> if a full refresh is required.</param>
		public EditorPropertyChangedEventArgs (IPropertyInfo property, PropertyVariation variation = null)
		{
			Property = property;
			Variation = variation;
		}

		/// <summary>
		/// Gets the property that was changed, or <c>null</c> for a full refresh.
		/// </summary>
		public IPropertyInfo Property
		{
			get;
		}

		/// <summary>
		/// Gets the variation that was changed, if any.
		/// </summary>
		public PropertyVariation Variation
		{
			get;
		}
	}

	public interface IObjectEditor
	{
		/// <summary>
		/// Gets the target object being edited.
		/// </summary>
		object Target { get; }

		/// <summary>
		/// Gets the real type of the <see cref="Target"/>.
		/// </summary>
		ITypeInfo TargetType { get; }

		/// <remarks>
		/// These properties should be minimally equatable to the same property for another object of the same type. This includes
		/// for base class properties for two different derived types.
		/// </remarks>
		IReadOnlyCollection<IPropertyInfo> Properties { get; }

		/// <summary>
		/// Gets a mapping between known properties (such as CommonBrush.Opacity) and their provider counterparts.
		/// </summary>
		/// <remarks>
		/// Should only include known properties present in <see cref="Properties"/>. Can be <c>null</c> if there are none.
		/// </remarks>
		IReadOnlyDictionary<IPropertyInfo, KnownProperty> KnownProperties { get; }

		/// <summary>
		/// Gets the parent object editor for the object this editor represents or <c>null</c> if none.
		/// </summary>
		IObjectEditor Parent { get; }

		/// <remarks>
		/// These are children that do not participate in the standard element hierarchy, such as segments in a segmented control.
		/// Note that objects defined by editors do not need to match real objects in the real hierarchy, they can be faked. An existing
		/// iOS property chooser itself can be mapped to having an object editor for its actual object.
		/// </remarks>
		IReadOnlyList<IObjectEditor> DirectChildren { get; }

		/// <summary>
		/// Raised when a property's value changes. <see cref="EditorPropertyChangedEventArgs.Property"/> can be <c>null</c> for a full refresh.
		/// </summary>
		event EventHandler<EditorPropertyChangedEventArgs> PropertyChanged;

		/// <param name="property">The property to get retrieve assignable types for.</param>
		/// <param name="childTypes">Whether or not to return assignable types for a property's children rather than the property itself.</param>
		/// <returns>An <see cref="AssignableTypesResult"/> instance containing the assignable types. No assignable types should use an empty array and not return <c>null</c>.</returns>
		Task<AssignableTypesResult> GetAssignableTypesAsync (IPropertyInfo property, bool childTypes);

		/*
		 * Dealing with async values in the context of what's possible across all target platforms is a bit complex.
		 * While implicit safety may be able to be ensured, it would be exhaustive to reason it out and could change
		 * at any moment, so we need an explicit safety strategy. As we make value gets and sets async, we open ourselves
		 * to race conditions even on just the UI thread. Value changes can come from the user, or from the object editor
		 * at any point. So, we break these changes into two categories: Blocking UI & Waiting Values.
		 *
		 * Anything that needs to deal with the current state of the values will Wait asynchronously on prior changes to
		 * finish. These largely involve value changes from the object editor, which just acts as a INPC and does not
		 * contain the value itself, so it will be safe and the latest value when queried upon reaching active state in
		 * the wait queue (see AsyncWorkQueue). Selected objects (when >1) need to wait on values as they need to be
		 * able to calculate the intersection values.
		 *
		 * Anything that needs to deal with user input will need to block its UI. We simply can't reason about the user
		 * changing values while waiting for previous changes, because they value they're changing may change underneath
		 * them or become invalid as a result of a prior pending change.
		 */

		/// <summary>
		/// Gets or sets variations of <paramref name="property"/> values.
		/// </summary>
		/// <param name="property"></param>
		/// <returns>
		/// Each <see cref="PropertyVariation"/> that has a value defined for the given <paramref name="property"/>.
		/// No variation set should be returned for a neutral value, it's assumed there is one.
		/// </returns>
		Task<IReadOnlyCollection<PropertyVariation>> GetPropertyVariantsAsync (IPropertyInfo property);

		/// <summary>
		/// Removes a variant version of a property.
		/// </summary>
		Task RemovePropertyVariantAsync (IPropertyInfo property, PropertyVariation variant);

		/// <remarks>
		/// <para>For the <see cref="ValueSource.Default"/> or <see cref="ValueSource.Unset"/> sources, implementers should
		/// ignore <paramref name="value"/>'s <see cref="ValueInfo{T}.Value"/> property and unset the value completely.
		/// For XML based backings this usually means removing the attribute altogether. Implementers should not simply set
		/// the value to its default value as this would still be a local value and override inheritance, styles, etc.</para>
		/// <para>When <paramref name="value"/>'s <see cref="ValueInfo{T}.Source"/> is <see cref="ValueSource.Resource"/>,
		/// the <see cref="ValueInfo{T}.SourceDescriptor"/> will be set to a <see cref="Resource"/> instance. Implementers
		/// need not see whether the resource contains a value itself. For a source of <see cref="ValueSource.Binding"/>,
		/// the <see cref="ValueInfo{T}.SourceDescriptor"/> will be the binding object created.</para>
		/// <para>When the <paramref name="property"/>'s <see cref="IPropertyInfo.Type"/> is an <c>object</c>
		/// <see cref="ValueInfo{T}.ValueDescriptor"/> will contain an <see cref="ITypeInfo"/> representing the real type
		/// of the value.</para>
		/// <para>When the <see cref="ValueInfo{T}.Source"/> is <see cref="ValueSource.Local"/> and <see cref="ValueInfo{T}.Value"/>
		/// is the same as the default value, implementers should consider unsetting the value such that the subsequent
		/// <see cref="GetValueAsync{T}(IPropertyInfo, PropertyVariation)"/> would return <see cref="ValueSource.Default"/>
		/// for <see cref="ValueInfo{T}.Source"/>. This allows users to clear the value for a property and have it remove
		/// the attribute for XML backed platforms without having to issue an <see cref="ValueSource.Unset"/>.</para>
		/// <para>Before the returned task completes, in order:
		/// 1. <see cref="GetValueAsync{T}(IPropertyInfo, PropertyVariation)"/> must be able to retrieve the new value.
		/// 2. <see cref="PropertyChanged"/> should fire with the appropriate property.
		/// For defensive purposes, consumers will not assume the <paramref name="value"/> they pass in will be the same
		/// as the new value and as a result will re-query the value upon the assumed <see cref="PropertyChanged"/> firing.
		/// There should not be a case where <see cref="PropertyChanged"/> is not fired when SetValueAsync is called, consumers
		/// will do basic verification before calling. Even <see cref="ValueInfo{T}.Source"/> changes with the value staying the
		/// same is a change in the property.
		/// </para>
		/// <para>
		/// For <paramref name="variations"/>, a set call for a <see cref="PropertyVariation"/> that is not yet set should be
		/// considered a "create new variation" call. Similarly, a call in which <paramref name="value"/>'s source is <see cref="ValueSource.Unset"/>
		/// should be considered a "delete variation" call when <paramref name="variations"/> is set.
		/// </para>
		/// </remarks>
		Task SetValueAsync<T> (IPropertyInfo property, ValueInfo<T> value, PropertyVariation variations = null);

		/// <remarks>
		/// <para>Implementers should strive to include the actual value of resources or bindings for <see cref="ValueInfo{T}.Value"/>
		/// wherever possible.</para>
		/// <para>If the platform can know the value of a property when unset, it should return that value and the <see cref="ValueSource.Default"/>
		/// source. If the platform only knows that the value is unset, use <see cref="ValueSource.Unset"/> instead.</para>
		///<para>When the property's value <see cref="ValueInfo{T}.Source"/> is <see cref="ValueSource.Resource"/>,
		/// the <see cref="ValueInfo{T}.SourceDescriptor"/> should be set to a <see cref="Resource"/> instance. Implementers should
		/// strive to retrieve the resource's value and use <see cref="Resource{T}"/> instead. For a source of
		/// <see cref="ValueSource.Binding"/>, the <see cref="ValueInfo{T}.SourceDescriptor"/> will be the binding object created.</para>
		/// <para>When the <paramref name="property"/>'s <see cref="IPropertyInfo.Type"/> is an <c>object</c>
		/// <see cref="ValueInfo{T}.ValueDescriptor"/> should contain an <see cref="ITypeInfo"/> representing the real type
		/// of the value.</para>
		/// </remarks>
		/// <exception cref="ArgumentNullException"><paramref name="property"/> is <c>null</c>.</exception>
		Task<ValueInfo<T>> GetValueAsync<T> (IPropertyInfo property, PropertyVariation variations = null);
	}
}