Browse files

Add WhenAnyObservable series of methods

Trying to WhenAny on an IObservable itself is clumsy (most notably,
ReactiveCommands and ReactiveCollection.ItemsAdded). Provide an additional
method to make this more straightforward.
  • Loading branch information...
1 parent 7815d68 commit 45dae9a428b494cee2e4bf44811e41d9fe86deea @paulcbetts paulcbetts committed Feb 13, 2013
View
42 ReactiveUI.Tests/ReactiveNotifyPropertyChangedMixinTest.cs
@@ -10,12 +10,25 @@
using System.Windows;
using System.Windows.Controls;
using ReactiveUI.Testing;
+using ReactiveUI.Xaml;
using Xunit;
using Microsoft.Reactive.Testing;
namespace ReactiveUI.Tests
{
+ public class TestWhenAnyObsViewModel : ReactiveObject
+ {
+ public ReactiveCommand Command1 { get; protected set; }
+ public ReactiveCommand Command2 { get; protected set; }
+
+ public TestWhenAnyObsViewModel()
+ {
+ Command1 = new ReactiveCommand();
+ Command2 = new ReactiveCommand();
+ }
+ }
+
public class HostTestFixture : ReactiveObject
{
public TestFixture _Child;
@@ -447,4 +460,33 @@ public void WhenAnyThroughAViewShouldntGiveNullValues()
new[] { "Foo", "Bar" }.AssertAreEqual(output);
}
}
+
+ public class WhenAnyObservableTests
+ {
+ [Fact]
+ public void WhenAnyObservableSmokeTest()
+ {
+ var fixture = new TestWhenAnyObsViewModel();
+
+ var list = new List<int>();
+ fixture.WhenAnyObservable(x => x.Command1, x => x.Command2)
+ .Subscribe(x => list.Add((int)x));
+
+ Assert.Equal(0, list.Count);
+
+ fixture.Command1.Execute(1);
+ Assert.Equal(1, list.Count);
+
+ fixture.Command2.Execute(2);
+ Assert.Equal(2, list.Count);
+
+ fixture.Command1.Execute(1);
+ Assert.Equal(3, list.Count);
+
+ Assert.True(
+ new[] {1, 2, 1,}.Zip(list, (expected, actual) => new {expected, actual})
+ .All(x => x.expected == x.actual));
+ }
+ }
+
}
View
1 ReactiveUI.Tests/ReactiveUI.Tests.csproj
@@ -133,6 +133,7 @@
<Compile Include="RxAppTest.cs" />
<Compile Include="RxRouting.cs" />
<Compile Include="Utility.cs" />
+ <Compile Include="WhenAnyObservableTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ReactiveUI.Routing\ReactiveUI.Routing.csproj">
View
64 ReactiveUI/VariadicTemplates.cs
@@ -771,4 +771,68 @@ public static class WhenAnyMixin
}
}
+
+ public static class WhenAnyObservableMixin
+ {
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1)
+ {
+ return This.WhenAny(obs1, x => x.Value).Merge();
+ }
+
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2)
+ {
+ return This.WhenAny(obs1, obs2, (o1, o2) => new[] {o1.Value, o2.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3)
+ {
+ return This.WhenAny(obs1, obs2, obs3, (o1, o2, o3) => new[] {o1.Value, o2.Value, o3.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, (o1, o2, o3, o4) => new[] {o1.Value, o2.Value, o3.Value, o4.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, (o1, o2, o3, o4, o5) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5, Expression<Func<TSender, IObservable<TRet>>> obs6)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, obs6, (o1, o2, o3, o4, o5, o6) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value, o6.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5, Expression<Func<TSender, IObservable<TRet>>> obs6, Expression<Func<TSender, IObservable<TRet>>> obs7)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, obs6, obs7, (o1, o2, o3, o4, o5, o6, o7) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value, o6.Value, o7.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5, Expression<Func<TSender, IObservable<TRet>>> obs6, Expression<Func<TSender, IObservable<TRet>>> obs7, Expression<Func<TSender, IObservable<TRet>>> obs8)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, obs6, obs7, obs8, (o1, o2, o3, o4, o5, o6, o7, o8) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value, o6.Value, o7.Value, o8.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5, Expression<Func<TSender, IObservable<TRet>>> obs6, Expression<Func<TSender, IObservable<TRet>>> obs7, Expression<Func<TSender, IObservable<TRet>>> obs8, Expression<Func<TSender, IObservable<TRet>>> obs9)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, obs6, obs7, obs8, obs9, (o1, o2, o3, o4, o5, o6, o7, o8, o9) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value, o6.Value, o7.Value, o8.Value, o9.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5, Expression<Func<TSender, IObservable<TRet>>> obs6, Expression<Func<TSender, IObservable<TRet>>> obs7, Expression<Func<TSender, IObservable<TRet>>> obs8, Expression<Func<TSender, IObservable<TRet>>> obs9, Expression<Func<TSender, IObservable<TRet>>> obs10)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, obs6, obs7, obs8, obs9, obs10, (o1, o2, o3, o4, o5, o6, o7, o8, o9, o10) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value, o6.Value, o7.Value, o8.Value, o9.Value, o10.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5, Expression<Func<TSender, IObservable<TRet>>> obs6, Expression<Func<TSender, IObservable<TRet>>> obs7, Expression<Func<TSender, IObservable<TRet>>> obs8, Expression<Func<TSender, IObservable<TRet>>> obs9, Expression<Func<TSender, IObservable<TRet>>> obs10, Expression<Func<TSender, IObservable<TRet>>> obs11)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, obs6, obs7, obs8, obs9, obs10, obs11, (o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value, o6.Value, o7.Value, o8.Value, o9.Value, o10.Value, o11.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4, Expression<Func<TSender, IObservable<TRet>>> obs5, Expression<Func<TSender, IObservable<TRet>>> obs6, Expression<Func<TSender, IObservable<TRet>>> obs7, Expression<Func<TSender, IObservable<TRet>>> obs8, Expression<Func<TSender, IObservable<TRet>>> obs9, Expression<Func<TSender, IObservable<TRet>>> obs10, Expression<Func<TSender, IObservable<TRet>>> obs11, Expression<Func<TSender, IObservable<TRet>>> obs12)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, obs5, obs6, obs7, obs8, obs9, obs10, obs11, obs12, (o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12) => new[] {o1.Value, o2.Value, o3.Value, o4.Value, o5.Value, o6.Value, o7.Value, o8.Value, o9.Value, o10.Value, o11.Value, o12.Value})
+ .SelectMany(x => x.Merge());
+ }
+ }
}
View
19 ReactiveUI/VariadicTemplates.tt
@@ -85,4 +85,23 @@ namespace ReactiveUI
<# } #>
}
+
+ public static class WhenAnyObservableMixin
+ {
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1)
+ {
+ return This.WhenAny(obs1, x => x.Value).Merge();
+ }
+
+ <# for(int length=2; length <= maxFuncLength; length++) { #>
+ <# string paramsStr = String.Join(", ", Enumerable.Range(1, length).Select(x => "Expression<Func<TSender, IObservable<TRet>>> obs" + x.ToString())); #>
+ <# string varsStr = String.Join(", ", Enumerable.Range(1, length).Select(x => "obs" + x.ToString())); #>
+ <# string valsStr = String.Join(", ", Enumerable.Range(1, length).Select(x => "o" + x.ToString() + ".Value")); #>
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, <#= paramsStr #>)
+ {
+ return This.WhenAny(<#= varsStr #>, (<#=varsStr.Replace("obs", "o")#>) => new[] {<#= valsStr #>})
+ .SelectMany(x => x.Merge());
+ }
+ <# } #>
+ }
}
View
344 ReactiveUI/VariadicTemplates_WP7.cs
@@ -12,9 +12,9 @@
namespace ReactiveUI
{
- public static class WhenAnyMixin
- {
-
+ public static class WhenAnyMixin
+ {
+
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
/// object have changed, providing an initial value when the Observable
@@ -23,25 +23,11 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAny<TSender, TRet, T1>(this TSender This,
- Expression<Func<TSender, T1>> property1,
- Func<IObservedChange<TSender, T1>, TRet> selector)
+ Expression<Func<TSender, T1>> property1,
+ Func<IObservedChange<TSender, T1>, TRet> selector)
{
- bool allInputsWorked = true;
- var slot1 = new ObservedChange<TSender, T1>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property1)),
- };
- T1 slot1Value = default(T1); allInputsWorked &= slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, T1> islot1 = slot1;
-
- return Observable.Create<TRet>(subject => {
- if (allInputsWorked) subject.OnNext(selector(islot1));
-
- return Observable.Merge(
- This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1))
- ).Subscribe(subject);
- });
- }
+ return This.ObservableForProperty(property1, beforeChange:false, skipInitial:false).Select(selector);
+ }
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
@@ -51,24 +37,14 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAnyDynamic<TSender, TRet>(this TSender This,
- string[] property1,
- Func<IObservedChange<TSender, object>, TRet> selector)
+ string[] property1,
+ Func<IObservedChange<TSender, object>, TRet> selector)
{
- var slot1 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property1),
- };
- object slot1Value = default(object); slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, object> islot1 = slot1;
-
- return Observable.Create<TRet>(subject => {
- subject.OnNext(selector(islot1));
-
- return Observable.Merge( This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1)) ).Subscribe(subject);
- });
- }
+ return ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property1, beforeChange:false, skipInitial:false).Select(selector);
+ }
-
+
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
/// object have changed, providing an initial value when the Observable
@@ -77,33 +53,16 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAny<TSender, TRet, T1,T2>(this TSender This,
- Expression<Func<TSender, T1>> property1,
- Expression<Func<TSender, T2>> property2,
- Func<IObservedChange<TSender, T1>, IObservedChange<TSender, T2>, TRet> selector)
+ Expression<Func<TSender, T1>> property1,
+ Expression<Func<TSender, T2>> property2,
+ Func<IObservedChange<TSender, T1>, IObservedChange<TSender, T2>, TRet> selector)
{
- bool allInputsWorked = true;
- var slot1 = new ObservedChange<TSender, T1>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property1)),
- };
- T1 slot1Value = default(T1); allInputsWorked &= slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, T1> islot1 = slot1;
- var slot2 = new ObservedChange<TSender, T2>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property2)),
- };
- T2 slot2Value = default(T2); allInputsWorked &= slot2.TryGetValue(out slot2Value); slot2.Value = slot2Value;
- IObservedChange<TSender, T2> islot2 = slot2;
-
- return Observable.Create<TRet>(subject => {
- if (allInputsWorked) subject.OnNext(selector(islot1, islot2));
-
- return Observable.Merge(
- This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1, islot2)),
- This.ObservableForProperty(property2).Do(x => { lock (slot2) { islot2 = x.fillInValue(); } }).Select(x => selector(islot1, islot2))
- ).Subscribe(subject);
- });
- }
+ return Observable.CombineLatest(
+ This.ObservableForProperty(property1, beforeChange: false, skipInitial:false),
+ This.ObservableForProperty(property2, beforeChange: false, skipInitial:false),
+ selector
+ );
+ }
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
@@ -113,31 +72,20 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAnyDynamic<TSender, TRet>(this TSender This,
- string[] property1,
- string[] property2,
- Func<IObservedChange<TSender, object>, IObservedChange<TSender, object>, TRet> selector)
+ string[] property1,
+ string[] property2,
+ Func<IObservedChange<TSender, object>, IObservedChange<TSender, object>, TRet> selector)
{
- var slot1 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property1),
- };
- object slot1Value = default(object); slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, object> islot1 = slot1;
- var slot2 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property2),
- };
- object slot2Value = default(object); slot2.TryGetValue(out slot2Value); slot2.Value = slot2Value;
- IObservedChange<TSender, object> islot2 = slot2;
-
- return Observable.Create<TRet>(subject => {
- subject.OnNext(selector(islot1, islot2));
-
- return Observable.Merge( This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1, islot2)), This.ObservableForProperty(property2).Do(x => { lock (slot2) { islot2 = x.fillInValue(); } }).Select(x => selector(islot1, islot2)) ).Subscribe(subject);
- });
- }
-
-
+ return Observable.CombineLatest(
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property1, beforeChange: false, skipInitial:false),
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property2, beforeChange: false, skipInitial:false),
+ selector
+ );
+ }
+
+
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
/// object have changed, providing an initial value when the Observable
@@ -146,41 +94,18 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAny<TSender, TRet, T1,T2,T3>(this TSender This,
- Expression<Func<TSender, T1>> property1,
- Expression<Func<TSender, T2>> property2,
- Expression<Func<TSender, T3>> property3,
- Func<IObservedChange<TSender, T1>, IObservedChange<TSender, T2>, IObservedChange<TSender, T3>, TRet> selector)
+ Expression<Func<TSender, T1>> property1,
+ Expression<Func<TSender, T2>> property2,
+ Expression<Func<TSender, T3>> property3,
+ Func<IObservedChange<TSender, T1>, IObservedChange<TSender, T2>, IObservedChange<TSender, T3>, TRet> selector)
{
- bool allInputsWorked = true;
- var slot1 = new ObservedChange<TSender, T1>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property1)),
- };
- T1 slot1Value = default(T1); allInputsWorked &= slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, T1> islot1 = slot1;
- var slot2 = new ObservedChange<TSender, T2>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property2)),
- };
- T2 slot2Value = default(T2); allInputsWorked &= slot2.TryGetValue(out slot2Value); slot2.Value = slot2Value;
- IObservedChange<TSender, T2> islot2 = slot2;
- var slot3 = new ObservedChange<TSender, T3>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property3)),
- };
- T3 slot3Value = default(T3); allInputsWorked &= slot3.TryGetValue(out slot3Value); slot3.Value = slot3Value;
- IObservedChange<TSender, T3> islot3 = slot3;
-
- return Observable.Create<TRet>(subject => {
- if (allInputsWorked) subject.OnNext(selector(islot1, islot2, islot3));
-
- return Observable.Merge(
- This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3)),
- This.ObservableForProperty(property2).Do(x => { lock (slot2) { islot2 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3)),
- This.ObservableForProperty(property3).Do(x => { lock (slot3) { islot3 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3))
- ).Subscribe(subject);
- });
- }
+ return Observable.CombineLatest(
+ This.ObservableForProperty(property1, beforeChange: false, skipInitial:false),
+ This.ObservableForProperty(property2, beforeChange: false, skipInitial:false),
+ This.ObservableForProperty(property3, beforeChange: false, skipInitial:false),
+ selector
+ );
+ }
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
@@ -190,38 +115,23 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAnyDynamic<TSender, TRet>(this TSender This,
- string[] property1,
- string[] property2,
- string[] property3,
- Func<IObservedChange<TSender, object>, IObservedChange<TSender, object>, IObservedChange<TSender, object>, TRet> selector)
+ string[] property1,
+ string[] property2,
+ string[] property3,
+ Func<IObservedChange<TSender, object>, IObservedChange<TSender, object>, IObservedChange<TSender, object>, TRet> selector)
{
- var slot1 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property1),
- };
- object slot1Value = default(object); slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, object> islot1 = slot1;
- var slot2 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property2),
- };
- object slot2Value = default(object); slot2.TryGetValue(out slot2Value); slot2.Value = slot2Value;
- IObservedChange<TSender, object> islot2 = slot2;
- var slot3 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property3),
- };
- object slot3Value = default(object); slot3.TryGetValue(out slot3Value); slot3.Value = slot3Value;
- IObservedChange<TSender, object> islot3 = slot3;
-
- return Observable.Create<TRet>(subject => {
- subject.OnNext(selector(islot1, islot2, islot3));
-
- return Observable.Merge( This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3)), This.ObservableForProperty(property2).Do(x => { lock (slot2) { islot2 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3)), This.ObservableForProperty(property3).Do(x => { lock (slot3) { islot3 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3)) ).Subscribe(subject);
- });
- }
-
-
+ return Observable.CombineLatest(
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property1, beforeChange: false, skipInitial:false),
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property2, beforeChange: false, skipInitial:false),
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property3, beforeChange: false, skipInitial:false),
+ selector
+ );
+ }
+
+
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
/// object have changed, providing an initial value when the Observable
@@ -230,49 +140,20 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAny<TSender, TRet, T1,T2,T3,T4>(this TSender This,
- Expression<Func<TSender, T1>> property1,
- Expression<Func<TSender, T2>> property2,
- Expression<Func<TSender, T3>> property3,
- Expression<Func<TSender, T4>> property4,
- Func<IObservedChange<TSender, T1>, IObservedChange<TSender, T2>, IObservedChange<TSender, T3>, IObservedChange<TSender, T4>, TRet> selector)
+ Expression<Func<TSender, T1>> property1,
+ Expression<Func<TSender, T2>> property2,
+ Expression<Func<TSender, T3>> property3,
+ Expression<Func<TSender, T4>> property4,
+ Func<IObservedChange<TSender, T1>, IObservedChange<TSender, T2>, IObservedChange<TSender, T3>, IObservedChange<TSender, T4>, TRet> selector)
{
- bool allInputsWorked = true;
- var slot1 = new ObservedChange<TSender, T1>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property1)),
- };
- T1 slot1Value = default(T1); allInputsWorked &= slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, T1> islot1 = slot1;
- var slot2 = new ObservedChange<TSender, T2>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property2)),
- };
- T2 slot2Value = default(T2); allInputsWorked &= slot2.TryGetValue(out slot2Value); slot2.Value = slot2Value;
- IObservedChange<TSender, T2> islot2 = slot2;
- var slot3 = new ObservedChange<TSender, T3>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property3)),
- };
- T3 slot3Value = default(T3); allInputsWorked &= slot3.TryGetValue(out slot3Value); slot3.Value = slot3Value;
- IObservedChange<TSender, T3> islot3 = slot3;
- var slot4 = new ObservedChange<TSender, T4>() {
- Sender = This,
- PropertyName = String.Join(".", Reflection.ExpressionToPropertyNames(property4)),
- };
- T4 slot4Value = default(T4); allInputsWorked &= slot4.TryGetValue(out slot4Value); slot4.Value = slot4Value;
- IObservedChange<TSender, T4> islot4 = slot4;
-
- return Observable.Create<TRet>(subject => {
- if (allInputsWorked) subject.OnNext(selector(islot1, islot2, islot3, islot4));
-
- return Observable.Merge(
- This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4)),
- This.ObservableForProperty(property2).Do(x => { lock (slot2) { islot2 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4)),
- This.ObservableForProperty(property3).Do(x => { lock (slot3) { islot3 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4)),
- This.ObservableForProperty(property4).Do(x => { lock (slot4) { islot4 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4))
- ).Subscribe(subject);
- });
- }
+ return Observable.CombineLatest(
+ This.ObservableForProperty(property1, beforeChange: false, skipInitial:false),
+ This.ObservableForProperty(property2, beforeChange: false, skipInitial:false),
+ This.ObservableForProperty(property3, beforeChange: false, skipInitial:false),
+ This.ObservableForProperty(property4, beforeChange: false, skipInitial:false),
+ selector
+ );
+ }
/// <summary>
/// WhenAny allows you to observe whenever one or more properties on an
@@ -282,43 +163,48 @@ public static class WhenAnyMixin
/// initial setup.
/// </summary>
public static IObservable<TRet> WhenAnyDynamic<TSender, TRet>(this TSender This,
- string[] property1,
- string[] property2,
- string[] property3,
- string[] property4,
- Func<IObservedChange<TSender, object>, IObservedChange<TSender, object>, IObservedChange<TSender, object>, IObservedChange<TSender, object>, TRet> selector)
+ string[] property1,
+ string[] property2,
+ string[] property3,
+ string[] property4,
+ Func<IObservedChange<TSender, object>, IObservedChange<TSender, object>, IObservedChange<TSender, object>, IObservedChange<TSender, object>, TRet> selector)
{
- var slot1 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property1),
- };
- object slot1Value = default(object); slot1.TryGetValue(out slot1Value); slot1.Value = slot1Value;
- IObservedChange<TSender, object> islot1 = slot1;
- var slot2 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property2),
- };
- object slot2Value = default(object); slot2.TryGetValue(out slot2Value); slot2.Value = slot2Value;
- IObservedChange<TSender, object> islot2 = slot2;
- var slot3 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property3),
- };
- object slot3Value = default(object); slot3.TryGetValue(out slot3Value); slot3.Value = slot3Value;
- IObservedChange<TSender, object> islot3 = slot3;
- var slot4 = new ObservedChange<TSender, object>() {
- Sender = This,
- PropertyName = String.Join(".", property4),
- };
- object slot4Value = default(object); slot4.TryGetValue(out slot4Value); slot4.Value = slot4Value;
- IObservedChange<TSender, object> islot4 = slot4;
-
- return Observable.Create<TRet>(subject => {
- subject.OnNext(selector(islot1, islot2, islot3, islot4));
+ return Observable.CombineLatest(
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property1, beforeChange: false, skipInitial:false),
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property2, beforeChange: false, skipInitial:false),
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property3, beforeChange: false, skipInitial:false),
+ ReactiveNotifyPropertyChangedMixin
+ .SubscribeToExpressionChain<TSender,object>(This, property4, beforeChange: false, skipInitial:false),
+ selector
+ );
+ }
- return Observable.Merge( This.ObservableForProperty(property1).Do(x => { lock (slot1) { islot1 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4)), This.ObservableForProperty(property2).Do(x => { lock (slot2) { islot2 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4)), This.ObservableForProperty(property3).Do(x => { lock (slot3) { islot3 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4)), This.ObservableForProperty(property4).Do(x => { lock (slot4) { islot4 = x.fillInValue(); } }).Select(x => selector(islot1, islot2, islot3, islot4)) ).Subscribe(subject);
- });
}
- }
+ public static class WhenAnyObservableMixin
+ {
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1)
+ {
+ return This.WhenAny(obs1, x => x.Value).Merge();
+ }
+
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2)
+ {
+ return This.WhenAny(obs1, obs2, (o1, o2) => new[] {o1.Value, o2.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3)
+ {
+ return This.WhenAny(obs1, obs2, obs3, (o1, o2, o3) => new[] {o1.Value, o2.Value, o3.Value})
+ .SelectMany(x => x.Merge());
+ }
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1, Expression<Func<TSender, IObservable<TRet>>> obs2, Expression<Func<TSender, IObservable<TRet>>> obs3, Expression<Func<TSender, IObservable<TRet>>> obs4)
+ {
+ return This.WhenAny(obs1, obs2, obs3, obs4, (o1, o2, o3, o4) => new[] {o1.Value, o2.Value, o3.Value, o4.Value})
+ .SelectMany(x => x.Merge());
+ }
+ }
}
View
19 ReactiveUI/VariadicTemplates_WP7.tt
@@ -85,4 +85,23 @@ namespace ReactiveUI
<# } #>
}
+
+ public static class WhenAnyObservableMixin
+ {
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, Expression<Func<TSender, IObservable<TRet>>> obs1)
+ {
+ return This.WhenAny(obs1, x => x.Value).Merge();
+ }
+
+ <# for(int length=2; length <= maxFuncLength; length++) { #>
+ <# string paramsStr = String.Join(", ", Enumerable.Range(1, length).Select(x => "Expression<Func<TSender, IObservable<TRet>>> obs" + x.ToString())); #>
+ <# string varsStr = String.Join(", ", Enumerable.Range(1, length).Select(x => "obs" + x.ToString())); #>
+ <# string valsStr = String.Join(", ", Enumerable.Range(1, length).Select(x => "o" + x.ToString() + ".Value")); #>
+ public static IObservable<TRet> WhenAnyObservable<TSender, TRet>(this TSender This, <#= paramsStr #>)
+ {
+ return This.WhenAny(<#= varsStr #>, (<#=varsStr.Replace("obs", "o")#>) => new[] {<#= valsStr #>})
+ .SelectMany(x => x.Merge());
+ }
+ <# } #>
+ }
}

0 comments on commit 45dae9a

Please sign in to comment.