Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions ReactiveUI.Tests/ObservableAsPropertyHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void OAPHShouldProvideLatestValue()
var input = new Subject<int>();

var fixture = new ObservableAsPropertyHelper<int>(input,
_ => { }, -5, sched);
_ => { }, -5, scheduler: sched);

Assert.Equal(-5, fixture.Value);
(new[] { 1, 2, 3, 4 }).Run(x => input.OnNext(x));
Expand All @@ -86,13 +86,54 @@ public void OAPHShouldProvideLatestValue()
Assert.Equal(4, fixture.Value);
}

[Fact]
public void OAPHShouldSubscribeImmediatelyToSource()
{
bool isSubscribed = false;

var observable = Observable.Create<int>(o =>
{
isSubscribed = true;
o.OnNext(42);
o.OnCompleted();

return Disposable.Empty;
});

var fixture = new ObservableAsPropertyHelper<int>(observable, _ => { }, 0);

Assert.True(isSubscribed);
Assert.Equal(42, fixture.Value);
}

[Fact]
public void OAPHDeferSubscriptionParameterDefersSubscriptionToSource()
{
bool isSubscribed = false;

var observable = Observable.Create<int>(o =>
{
isSubscribed = true;
o.OnNext(42);
o.OnCompleted();

return Disposable.Empty;
});

var fixture = new ObservableAsPropertyHelper<int>(observable, _ => { }, 0, true);

Assert.False(isSubscribed);
Assert.Equal(42, fixture.Value);
Assert.True(isSubscribed);
}

[Fact]
public void OAPHShouldRethrowErrors()
{
var input = new Subject<int>();
var sched = new TestScheduler();

var fixture = new ObservableAsPropertyHelper<int>(input, _ => { }, -5, sched);
var fixture = new ObservableAsPropertyHelper<int>(input, _ => { }, -5, scheduler: sched);
var errors = new List<Exception>();

Assert.Equal(-5, fixture.Value);
Expand Down
41 changes: 35 additions & 6 deletions ReactiveUI/ObservableAsPropertyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,21 @@ public sealed class ObservableAsPropertyHelper<T> : IHandleObservableErrors, IDi
/// changes, typically this will call the ViewModel's
/// RaisePropertyChanged method.</param>
/// <param name="initialValue">The initial value of the property.</param>
/// <param name="deferSubscription">
/// A value indicating whether the <see cref="ObservableAsPropertyHelper{T}"/>
/// should defer the subscription to the <paramref name="observable"/> source
/// until the first call to <see cref="Value"/>, or if it should immediately
/// subscribe to the the <paramref name="observable"/> source.
/// </param>
/// <param name="scheduler">The scheduler that the notifications will be
/// provided on - this should normally be a Dispatcher-based scheduler
/// (and is by default)</param>
public ObservableAsPropertyHelper(
IObservable<T> observable,
Action<T> onChanged,
T initialValue = default(T),
IScheduler scheduler = null) : this(observable, onChanged, null, initialValue, scheduler) {}
bool deferSubscription = false,
IScheduler scheduler = null) : this(observable, onChanged, null, initialValue, deferSubscription, scheduler) {}

/// <summary>
/// Constructs an ObservableAsPropertyHelper object.
Expand All @@ -54,6 +61,12 @@ public ObservableAsPropertyHelper(
/// changes, typically this will call the ViewModel's
/// RaisePropertyChanging method.</param>
/// <param name="initialValue">The initial value of the property.</param>
/// <param name="deferSubscription">
/// A value indicating whether the <see cref="ObservableAsPropertyHelper{T}"/>
/// should defer the subscription to the <paramref name="observable"/> source
/// until the first call to <see cref="Value"/>, or if it should immediately
/// subscribe to the the <paramref name="observable"/> source.
/// </param>
/// <param name="scheduler">The scheduler that the notifications will be
/// provided on - this should normally be a Dispatcher-based scheduler
/// (and is by default)</param>
Expand All @@ -62,6 +75,7 @@ public ObservableAsPropertyHelper(
Action<T> onChanged,
Action<T> onChanging = null,
T initialValue = default(T),
bool deferSubscription = false,
IScheduler scheduler = null)
{
Contract.Requires(observable != null);
Expand All @@ -83,7 +97,7 @@ public ObservableAsPropertyHelper(

_lastValue = initialValue;
_source = observable.StartWith(initialValue).DistinctUntilChanged().Multicast(subj);
if (ModeDetector.InUnitTestRunner())
if (!deferSubscription)
{
_inner = _source.Connect();
_activated = 1;
Expand Down Expand Up @@ -126,7 +140,7 @@ public void Dispose()
/// (and is by default)</param>
public static ObservableAsPropertyHelper<T> Default(T initialValue = default(T), IScheduler scheduler = null)
{
return new ObservableAsPropertyHelper<T>(Observable.Never<T>(), _ => {}, initialValue, scheduler);
return new ObservableAsPropertyHelper<T>(Observable.Never<T>(), _ => {}, initialValue, false, scheduler);
}
}

Expand All @@ -137,6 +151,7 @@ static ObservableAsPropertyHelper<TRet> observableToProperty<TObj, TRet>(
IObservable<TRet> observable,
Expression<Func<TObj, TRet>> property,
TRet initialValue = default(TRet),
bool deferSubscription = false,
IScheduler scheduler = null)
where TObj : IReactiveObject
{
Expand All @@ -154,7 +169,7 @@ static ObservableAsPropertyHelper<TRet> observableToProperty<TObj, TRet>(
var ret = new ObservableAsPropertyHelper<TRet>(observable,
_ => This.raisePropertyChanged(name),
_ => This.raisePropertyChanging(name),
initialValue, scheduler);
initialValue, deferSubscription, scheduler);

return ret;
}
Expand All @@ -168,6 +183,12 @@ static ObservableAsPropertyHelper<TRet> observableToProperty<TObj, TRet>(
/// <param name="property">An Expression representing the property (i.e.
/// 'x => x.SomeProperty'</param>
/// <param name="initialValue">The initial value of the property.</param>
/// <param name="deferSubscription">
/// A value indicating whether the <see cref="ObservableAsPropertyHelper{T}"/>
/// should defer the subscription to the <paramref name="observable"/> source
/// until the first call to <see cref="Value"/>, or if it should immediately
/// subscribe to the the <paramref name="observable"/> source.
/// </param>
/// <param name="scheduler">The scheduler that the notifications will be
/// provided on - this should normally be a Dispatcher-based scheduler
/// (and is by default)</param>
Expand All @@ -178,10 +199,11 @@ public static ObservableAsPropertyHelper<TRet> ToProperty<TObj, TRet>(
TObj source,
Expression<Func<TObj, TRet>> property,
TRet initialValue = default(TRet),
bool deferSubscription = false,
IScheduler scheduler = null)
where TObj : IReactiveObject
{
return source.observableToProperty(This, property, initialValue, scheduler);
return source.observableToProperty(This, property, initialValue, deferSubscription, scheduler);
}

/// <summary>
Expand All @@ -193,6 +215,12 @@ public static ObservableAsPropertyHelper<TRet> ToProperty<TObj, TRet>(
/// <param name="property">An Expression representing the property (i.e.
/// 'x => x.SomeProperty'</param>
/// <param name="initialValue">The initial value of the property.</param>
/// <param name="deferSubscription">
/// A value indicating whether the <see cref="ObservableAsPropertyHelper{T}"/>
/// should defer the subscription to the <paramref name="observable"/> source
/// until the first call to <see cref="Value"/>, or if it should immediately
/// subscribe to the the <paramref name="observable"/> source.
/// </param>
/// <param name="scheduler">The scheduler that the notifications will be
/// provided on - this should normally be a Dispatcher-based scheduler
/// (and is by default)</param>
Expand All @@ -204,10 +232,11 @@ public static ObservableAsPropertyHelper<TRet> ToProperty<TObj, TRet>(
Expression<Func<TObj, TRet>> property,
out ObservableAsPropertyHelper<TRet> result,
TRet initialValue = default(TRet),
bool deferSubscription = false,
IScheduler scheduler = null)
where TObj : IReactiveObject
{
var ret = source.observableToProperty(This, property, initialValue, scheduler);
var ret = source.observableToProperty(This, property, initialValue, deferSubscription, scheduler);

result = ret;
return ret;
Expand Down