forked from reactiveui/ReactiveUI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAndroidObservableForWidgets.cs
More file actions
103 lines (90 loc) · 4.97 KB
/
AndroidObservableForWidgets.cs
File metadata and controls
103 lines (90 loc) · 4.97 KB
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
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reactive.Linq;
using System.Collections.Generic;
using Android.Views;
using Android.Widget;
using System.Reactive;
using Android.Text;
using Java.Util;
using Observable = System.Reactive.Linq.Observable;
namespace ReactiveUI
{
/// <summary>
/// Android view objects are not Generally Observable™, so hard-code some
/// particularly useful types.
/// </summary>
public class AndroidObservableForWidgets : ICreatesObservableForProperty
{
static readonly IDictionary<Tuple<Type, string>, Func<object, Expression, IObservable<IObservedChange<object, object>>>> dispatchTable;
static AndroidObservableForWidgets()
{
dispatchTable = new[] {
createFromWidget<TextView, TextChangedEventArgs>(v => v.Text, (v, h) => v.TextChanged += h, (v, h) => v.TextChanged -= h),
createFromWidget<NumberPicker, NumberPicker.ValueChangeEventArgs>(v => v.Value, (v, h) => v.ValueChanged += h, (v, h) => v.ValueChanged -= h),
createFromWidget<RatingBar, RatingBar.RatingBarChangeEventArgs>(v => v.Rating, (v, h) => v.RatingBarChange += h, (v, h) => v.RatingBarChange -= h),
createFromWidget<CompoundButton, CompoundButton.CheckedChangeEventArgs>(v => v.Checked, (v, h) => v.CheckedChange += h, (v, h) => v.CheckedChange -= h),
createFromWidget<CalendarView, CalendarView.DateChangeEventArgs>(v => v.Date, (v, h) => v.DateChange += h, (v, h) => v.DateChange -= h),
createFromWidget<TabHost, TabHost.TabChangeEventArgs>(v => v.CurrentTab, (v, h) => v.TabChanged += h, (v, h) => v.TabChanged -= h),
createFromWidget<TimePicker, TimePicker.TimeChangedEventArgs>(v => v.CurrentHour, (v, h) => v.TimeChanged += h, (v, h) => v.TimeChanged -= h),
createFromWidget<TimePicker, TimePicker.TimeChangedEventArgs>(v => v.CurrentMinute, (v, h) => v.TimeChanged += h, (v, h) => v.TimeChanged -= h),
createFromAdapterView(),
}.ToDictionary(k => Tuple.Create(k.Type, k.Property), v => v.Func);
}
public int GetAffinityForObject(Type type, string propertyName, bool beforeChanged = false)
{
if (beforeChanged) return 0;
return dispatchTable.Keys.Any(x => x.Item1.IsAssignableFrom(type) && x.Item2 == propertyName) ? 5 : 0;
}
public IObservable<IObservedChange<object, object>> GetNotificationForProperty(object sender, Expression expression, bool beforeChanged = false)
{
var type = sender.GetType();
var tableItem = dispatchTable.Keys.First(x => x.Item1.IsAssignableFrom(type) && x.Item2 == expression.GetMemberInfo().Name);
return dispatchTable[tableItem](sender, expression);
}
class DispatchTuple
{
public Type Type { get; set; }
public string Property { get; set; }
public Func<object, Expression, IObservable<IObservedChange<object, object>>> Func { get; set; }
}
static DispatchTuple createFromAdapterView()
{
// AdapterView is more complicated because there are two events - one for select and one for deselect
// respond to both
const string propName = "SelectedItem";
return new DispatchTuple
{
Type = typeof(AdapterView),
Property = propName,
Func = (x, ex) => {
var v = (AdapterView)x;
return Observable.Merge(
Observable.FromEventPattern<AdapterView.ItemSelectedEventArgs>(h => v.ItemSelected += h, h => v.ItemSelected -=h)
.Select(_ => new ObservedChange<object, object>(v, ex)),
Observable.FromEventPattern<AdapterView.NothingSelectedEventArgs>(h => v.NothingSelected += h, h => v.NothingSelected -= h)
.Select(_ => new ObservedChange<object, object>(v, ex))
);
}
};
}
static DispatchTuple createFromWidget<TView, TEventArgs>(Expression<Func<TView, object>> property, Action<TView, EventHandler<TEventArgs>> addHandler, Action<TView, EventHandler<TEventArgs>> removeHandler)
where TView : View
where TEventArgs : EventArgs
{
// ExpressionToPropertyNames is used here as it handles boxing expressions that might
// occur due to our use of object
var propName = property.Body.GetMemberInfo().Name;
return new DispatchTuple {
Type = typeof(TView),
Property = propName,
Func = (x, ex) => {
var v = (TView)x;
return Observable.FromEventPattern<TEventArgs>(h => addHandler(v, h) , h => removeHandler(v, h))
.Select(_ => new ObservedChange<object, object>(v, ex));
}
};
}
}
}