/
RegisterableInterfaces.cs
293 lines (272 loc) · 13.6 KB
/
RegisterableInterfaces.cs
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Concurrency;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace ReactiveUI
{
public enum BindingDirection
{
OneWay,
TwoWay,
AsyncOneWay,
}
/// <summary>
/// IMessageBus represents an object that can act as a "Message Bus", a
/// simple way for ViewModels and other objects to communicate with each
/// other in a loosely coupled way.
///
/// Specifying which messages go where is done via a combination of the Type
/// of the message as well as an additional "Contract" parameter; this is a
/// unique string used to distinguish between messages of the same Type, and
/// is arbitrarily set by the client.
/// </summary>
public interface IMessageBus : IEnableLogger
{
/// <summary>
/// Registers a scheduler for the type, which may be specified at
/// runtime, and the contract.
/// </summary>
/// <remarks>If a scheduler is already registered for the specified
/// runtime and contract, this will overrwrite the existing
/// registration.</remarks>
/// <typeparam name="T">The type of the message to listen to.</typeparam>
/// <param name="scheduler">The scheduler on which to post the
/// notifications for the specified type and contract.
/// RxApp.MainThreadScheduler by default.</param>
/// <param name="contract">A unique string to distinguish messages with
/// identical types (i.e. "MyCoolViewModel") - if the message type is
/// only used for one purpose, leave this as null.</param>
void RegisterScheduler<T>(IScheduler scheduler, string contract = null);
/// <summary>
/// Listen provides an Observable that will fire whenever a Message is
/// provided for this object via RegisterMessageSource or SendMessage.
/// </summary>
/// <typeparam name="T">The type of the message to listen to.</typeparam>
/// <param name="contract">A unique string to distinguish messages with
/// identical types (i.e. "MyCoolViewModel") - if the message type is
/// only used for one purpose, leave this as null.</param>
/// <returns></returns>
IObservable<T> Listen<T>(string contract = null);
/// <summary>
/// ListenIncludeLatest provides an Observable that will fire whenever a Message is
/// provided for this object via RegisterMessageSource or SendMessage and fire the
/// last provided Message immediately if applicable, or null.
/// </summary>
/// <typeparam name="T">The type of the message to listen to.</typeparam>
/// <param name="contract">A unique string to distinguish messages with
/// identical types (i.e. "MyCoolViewModel") - if the message type is
/// only used for one purpose, leave this as null.</param>
/// <returns>An Observable representing the notifications posted to the
/// message bus.</returns>
IObservable<T> ListenIncludeLatest<T>(string contract = null);
/// <summary>
/// Determines if a particular message Type is registered.
/// </summary>
/// <param name="type">The type of the message.</param>
/// <param name="contract">A unique string to distinguish messages with
/// identical types (i.e. "MyCoolViewModel") - if the message type is
/// only used for one purpose, leave this as null.</param>
/// <returns>True if messages have been posted for this message Type.</returns>
bool IsRegistered(Type type, string contract = null);
/// <summary>
/// Registers an Observable representing the stream of messages to send.
/// Another part of the code can then call Listen to retrieve this
/// Observable.
/// </summary>
/// <typeparam name="T">The type of the message to listen to.</typeparam>
/// <param name="source">An Observable that will be subscribed to, and a
/// message sent out for each value provided.</param>
/// <param name="contract">A unique string to distinguish messages with
/// identical types (i.e. "MyCoolViewModel") - if the message type is
/// only used for one purpose, leave this as null.</param>
IDisposable RegisterMessageSource<T>(IObservable<T> source, string contract = null);
/// <summary>
/// Sends a single message using the specified Type and contract.
/// Consider using RegisterMessageSource instead if you will be sending
/// messages in response to other changes such as property changes
/// or events.
/// </summary>
/// <typeparam name="T">The type of the message to send.</typeparam>
/// <param name="message">The actual message to send</param>
/// <param name="contract">A unique string to distinguish messages with
/// identical types (i.e. "MyCoolViewModel") - if the message type is
/// only used for one purpose, leave this as null.</param>
void SendMessage<T>(T message, string contract = null);
}
/// <summary>
/// ICreatesObservableForProperty represents an object that knows how to
/// create notifications for a given type of object. Implement this if you
/// are porting RxUI to a new UI toolkit, or generally want to enable WhenAny
/// for another type of object that can be observed in a unique way.
/// </summary>
public interface ICreatesObservableForProperty : IEnableLogger
{
/// <summary>
/// Returns a positive integer when this class supports
/// GetNotificationForProperty for this particular Type. If the method
/// isn't supported at all, return a non-positive integer. When multiple
/// implementations return a positive value, the host will use the one
/// which returns the highest value. When in doubt, return '2' or '0'
/// </summary>
/// <param name="type">The type to query for.</param>
/// <returns>A positive integer if GNFP is supported, zero or a negative
/// value otherwise</returns>
int GetAffinityForObject(Type type, string propertyName, bool beforeChanged = false);
/// <summary>
/// Subscribe to notifications on the specified property, given an
/// object and a property name.
/// </summary>
/// <param name="sender">The object to observe.</param>
/// <param name="propertyName">The property on the object to observe.
/// This property will not be a dotted property, only a simple name.
/// </param>
/// <param name="beforeChanged">If true, signal just before the
/// property value actually changes. If false, signal after the
/// property changes.</param>
/// <returns>An IObservable which is signalled whenever the specified
/// property on the object changes. If this cannot be done for a
/// specified value of beforeChanged, return Observable.Never</returns>
IObservable<IObservedChange<object, object>> GetNotificationForProperty(object sender, string propertyName, bool beforeChanged = false);
}
/// <summary>
/// This interface is the extensible implementation of IValueConverters for
/// Bind and OneWayBind. Implement this to teach Bind and OneWayBind how to
/// convert between types.
/// </summary>
public interface IBindingTypeConverter : IEnableLogger
{
/// <summary>
/// Returns a positive integer when this class supports
/// TryConvert for this particular Type. If the method isn't supported at
/// all, return a non-positive integer. When multiple implementations
/// return a positive value, the host will use the one which returns
/// the highest value. When in doubt, return '2' or '0'.
/// </summary>
/// <param name="lhs">The left-hand object to compare (i.e. 'from')</param>
/// <param name="rhs">The right-hand object to compare (i.e. 'to')</param>
/// <returns>A positive integer if TryConvert is supported,
/// zero or a negative value otherwise</returns>
int GetAffinityForObjects(Type lhs, Type rhs);
/// <summary>
/// Convert a given object to the specified type.
/// </summary>
/// <param name="from">The object to convert.</param>
/// <param name="toType">The type to coerce the object to.</param>
/// <param name="conversionHint">An implementation-defined value,
/// usually to specify things like locale awareness.</param>
/// <returns>An object that is of the type 'to'</returns>
bool TryConvert(object from, Type toType, object conversionHint, out object result);
}
/// <summary>
/// Implement this to teach Bind and OneWayBind how to guess the most
/// "common" property on a given control, so if the caller doesn't specify it,
/// it'll pick the right control
/// </summary>
public interface IDefaultPropertyBindingProvider
{
/// <summary>
/// Given a certain control, figure out the default property to bind to
/// </summary>
/// <param name="control">The control to look at.</param>
/// <returns>A tuple of PropertyName and Affinity for that property.
/// Use the same rules about affinity as others, but return null if
/// the property can't be determined.</returns>
Tuple<string, int> GetPropertyForControl(object control);
}
public interface IPropertyBindingHook
{
bool ExecuteHook(
object source, object target,
Func<IObservedChange<object, object>[]> getCurrentViewModelProperties,
Func<IObservedChange<object, object>[]> getCurrentViewProperties,
BindingDirection direction);
}
public interface IViewFor
{
object ViewModel { get; set; }
}
/// <summary>
/// Implement this interface on your Views to support Routing and Binding.
/// </summary>
public interface IViewFor<T> : IViewFor
where T : class
{
/// <summary>
/// The ViewModel corresponding to this specific View. This should be
/// a DependencyProperty if you're using XAML.
/// </summary>
new T ViewModel { get; set; }
}
/// <summary>
/// IScreen represents any object that is hosting its own routing -
/// usually this object is your AppViewModel or MainWindow object.
/// </summary>
public interface IScreen
{
/// <summary>
/// The Router associated with this Screen.
/// </summary>
IRoutingState Router { get; }
}
public interface ICreatesCommandBinding
{
/// <summary>
/// Returns a positive integer when this class supports
/// BindCommandToObject for this particular Type. If the method
/// isn't supported at all, return a non-positive integer. When multiple
/// implementations return a positive value, the host will use the one
/// which returns the highest value. When in doubt, return '2' or '0'
/// </summary>
/// <param name="type">The type to query for.</param>
/// <param name="hasEventTarget">If true, the host intends to use a custom
/// event target.</param>
/// <returns>A positive integer if BCTO is supported, zero or a negative
/// value otherwise</returns>
int GetAffinityForObject(Type type, bool hasEventTarget);
/// <summary>
/// Bind an ICommand to a UI object, in the "default" way. The meaning
/// of this is dependent on the implementation. Implement this if you
/// have a new type of UI control that doesn't have
/// Command/CommandParameter like WPF or has a non-standard event name
/// for "Invoke".
/// </summary>
/// <param name="command">The command to bind</param>
/// <param name="target">The target object, usually a UI control of
/// some kind</param>
/// <param name="commandParameter">An IObservable source whose latest
/// value will be passed as the command parameter to the command. Hosts
/// will always pass a valid IObservable, but this may be
/// Observable.Empty</param>
/// <returns>An IDisposable which will disconnect the binding when
/// disposed.</returns>
IDisposable BindCommandToObject(ICommand command, object target, IObservable<object> commandParameter);
/// <summary>
/// Bind an ICommand to a UI object to a specific event. This event may
/// be a standard .NET event, or it could be an event derived in another
/// manner (i.e. in MonoTouch).
/// </summary>
/// <param name="command">The command to bind</param>
/// <param name="target">The target object, usually a UI control of
/// some kind</param>
/// <param name="commandParameter">An IObservable source whose latest
/// value will be passed as the command parameter to the command. Hosts
/// will always pass a valid IObservable, but this may be
/// Observable.Empty</param>
/// <param name="eventName">The event to bind to.</param>
/// <returns></returns>
/// <returns>An IDisposable which will disconnect the binding when
/// disposed.</returns>
IDisposable BindCommandToObject<TEventArgs>(ICommand command, object target, IObservable<object> commandParameter, string eventName);
}
internal interface IPlatformOperations
{
string GetOrientation();
}
internal interface IWantsToRegisterStuff
{
void Register(Action<Func<object>, Type> registerFunction);
}
}