Browse Source

More work on allowing bindings in setters.

Support activated ISubjects.
Steven Kirk 10 years ago
parent
commit
36f2f3e1e0

+ 30 - 0
src/Perspex.Base/PerspexObjectExtensions.cs

@@ -103,6 +103,36 @@ namespace Perspex
                 GetDescription(o, property));
         }
 
+        /// <summary>
+        /// Gets a subject for a <see cref="PerspexProperty"/>.
+        /// </summary>
+        /// <param name="o">The object.</param>
+        /// <param name="property">The property.</param>
+        /// <param name="priority">
+        /// The priority with which binding values are written to the object.
+        /// </param>
+        /// <returns>
+        /// An <see cref="ISubject{Object}"/> which can be used for two-way binding to/from the 
+        /// property.
+        /// </returns>
+        public static ISubject<object> GetSubject(
+            this IPerspexObject o,
+            PerspexProperty property,
+            BindingPriority priority = BindingPriority.LocalValue)
+        {
+            // TODO: Subject.Create<T> is not yet in stable Rx : once it is, remove the 
+            // AnonymousSubject classes from this file and use Subject.Create<T>.
+            var output = new Subject<object>();
+            var result = new AnonymousSubject<object>(
+                Observer.Create<object>(
+                    x => output.OnNext(x),
+                    e => output.OnError(e),
+                    () => output.OnCompleted()),
+                o.GetObservable(property));
+            o.Bind(property, output, priority);
+            return result;
+        }
+
         /// <summary>
         /// Gets a subject for a <see cref="PerspexProperty"/>.
         /// </summary>

+ 3 - 1
src/Perspex.Styling/Perspex.Styling.csproj

@@ -45,6 +45,8 @@
     <Compile Include="ILogical.cs" />
     <Compile Include="LogicalTree\LogicalExtensions.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Styling\ActivatedSubject.cs" />
+    <Compile Include="Styling\ActivatedValue.cs" />
     <Compile Include="Styling\IGlobalStyles.cs" />
     <Compile Include="Styling\ISetter.cs" />
     <Compile Include="Styling\IStyle.cs" />
@@ -59,7 +61,7 @@
     <Compile Include="Styling\Setter.cs" />
     <Compile Include="Styling\Style.cs" />
     <Compile Include="Styling\StyleActivator.cs" />
-    <Compile Include="Styling\StyleBinding.cs" />
+    <Compile Include="Styling\ActivatedObservable.cs" />
     <Compile Include="Styling\Styler.cs" />
     <Compile Include="Styling\Styles.cs" />
   </ItemGroup>

+ 80 - 0
src/Perspex.Styling/Styling/ActivatedObservable.cs

@@ -0,0 +1,80 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Reactive;
+using System.Reactive.Linq;
+
+namespace Perspex.Styling
+{
+    /// <summary>
+    /// An observable which is switched on or off according to an activator observable.
+    /// </summary>
+    /// <remarks>
+    /// An <see cref="ActivatedObservable"/> has two inputs: an activator observable a 
+    /// <see cref="Source"/> observable which produces the activated value. When the activator 
+    /// produces true, the <see cref="ActivatedObservable"/> will produce the current activated 
+    /// value. When the activator produces false it will produce
+    /// <see cref="PerspexProperty.UnsetValue"/>.
+    /// </remarks>
+    internal class ActivatedObservable : ObservableBase<object>, IDescription
+    {
+        /// <summary>
+        /// The activator.
+        /// </summary>
+        private readonly IObservable<bool> _activator;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ActivatedObservable"/> class.
+        /// </summary>
+        /// <param name="activator">The activator.</param>
+        /// <param name="source">An observable that produces the activated value.</param>
+        /// <param name="description">The binding description.</param>
+        public ActivatedObservable(
+            IObservable<bool> activator,
+            IObservable<object> source,
+            string description)
+        {
+            _activator = activator;
+            Description = description;
+            Source = source;
+        }
+
+        /// <summary>
+        /// Gets a description of the binding.
+        /// </summary>
+        public string Description
+        {
+            get;
+        }
+
+        /// <summary>
+        /// Gets an observable which produces the <see cref="ActivatedValue"/>.
+        /// </summary>
+        public IObservable<object> Source
+        {
+            get;
+        }
+
+        /// <summary>
+        /// Notifies the provider that an observer is to receive notifications.
+        /// </summary>
+        /// <param name="observer">The observer.</param>
+        /// <returns>IDisposable object used to unsubscribe from the observable sequence.</returns>
+        protected override IDisposable SubscribeCore(IObserver<object> observer)
+        {
+            Contract.Requires<ArgumentNullException>(observer != null);
+
+            var sourceCompleted = Source.TakeLast(1).Select(_ => Unit.Default);
+            var activatorCompleted = _activator.TakeLast(1).Select(_ => Unit.Default);
+            var completed = sourceCompleted.Merge(activatorCompleted);
+
+            return _activator
+                .CombineLatest(Source, (x, y) => new { Active = x, Value = y })
+                .Select(x => x.Active ? x.Value : PerspexProperty.UnsetValue)
+                .DistinctUntilChanged()
+                .TakeUntil(completed)
+                .Subscribe(observer);
+        }
+    }
+}

+ 124 - 0
src/Perspex.Styling/Styling/ActivatedSubject.cs

@@ -0,0 +1,124 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+
+namespace Perspex.Styling
+{
+    /// <summary>
+    /// A subject which is switched on or off according to an activator observable.
+    /// </summary>
+    /// <remarks>
+    /// An <see cref="ActivatedSubject"/> has two inputs: an activator observable and either an
+    /// <see cref="ActivatedValue"/> or a <see cref="Source"/> observable which produces the
+    /// activated value. When the activator produces true, the <see cref="ActivatedObservable"/> will
+    /// produce the current activated value. When the activator produces false it will produce
+    /// <see cref="PerspexProperty.UnsetValue"/>.
+    /// </remarks>
+    internal class ActivatedSubject : ISubject<object>, IDescription
+    {
+        private IObservable<bool> _activator;
+        private bool _active;
+        private object _pushValue;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ActivatedSubject"/> class.
+        /// </summary>
+        /// <param name="activator">The activator.</param>
+        /// <param name="source">An observable that produces the activated value.</param>
+        /// <param name="description">The binding description.</param>
+        public ActivatedSubject(
+            IObservable<bool> activator,
+            ISubject<object> source,
+            string description)
+        {
+            _activator = activator;
+            Description = description;
+            Source = source;
+
+            _activator.Skip(1).Subscribe(ActivatorChanged);
+        }
+
+        /// <summary>
+        /// Gets a description of the binding.
+        /// </summary>
+        public string Description
+        {
+            get;
+        }
+
+        /// <summary>
+        /// Gets the underlying subject.
+        /// </summary>
+        public ISubject<object> Source
+        {
+            get;
+        }
+
+        /// <summary>
+        /// Notifies all subscribed observers about the end of the sequence.
+        /// </summary>
+        public void OnCompleted()
+        {
+            if (_active)
+            {
+                Source.OnCompleted();
+            }
+        }
+
+        /// <summary>
+        /// Notifies all subscribed observers with the exception.
+        /// </summary>
+        /// <param name="error">The exception to send to all subscribed observers.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="error"/> is null.</exception>
+        public void OnError(Exception error)
+        {
+            if (_active)
+            {
+                Source.OnError(error);
+            }
+        }
+
+        /// <summary>
+        /// Notifies all subscribed observers with the value.
+        /// </summary>
+        /// <param name="value">The value to send to all subscribed observers.</param>        
+        public void OnNext(object value)
+        {
+            _pushValue = value;
+
+            if (_active)
+            {
+                Source.OnNext(value);
+            }
+        }
+
+        /// <summary>
+        /// Notifies the provider that an observer is to receive notifications.
+        /// </summary>
+        /// <param name="observer">The observer.</param>
+        /// <returns>IDisposable object used to unsubscribe from the observable sequence.</returns>
+        public IDisposable Subscribe(IObserver<object> observer)
+        {
+            Contract.Requires<ArgumentNullException>(observer != null);
+
+            var completed = _activator.TakeLast(1).Select(_ => Unit.Default);
+
+            return _activator
+                .CombineLatest(Source, (x, y) => new { Active = x, Value = y })
+                .Select(x => x.Active ? x.Value : PerspexProperty.UnsetValue)
+                .DistinctUntilChanged()
+                .TakeUntil(completed)
+                .Subscribe(observer);
+        }
+
+        private void ActivatorChanged(bool active)
+        {
+            _active = active;
+            Source.OnNext(active ? _pushValue : PerspexProperty.UnsetValue);
+        }
+    }
+}

+ 72 - 0
src/Perspex.Styling/Styling/ActivatedValue.cs

@@ -0,0 +1,72 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Reactive;
+using System.Reactive.Linq;
+
+namespace Perspex.Styling
+{
+    /// <summary>
+    /// An value which is switched on or off according to an activator observable.
+    /// </summary>
+    /// <remarks>
+    /// An <see cref="ActivatedValue"/> has two inputs: an activator observable and an
+    /// <see cref="Value"/>. When the activator produces true, the 
+    /// <see cref="ActivatedValue"/> will produce the current value. When the activator 
+    /// produces false it will produce <see cref="PerspexProperty.UnsetValue"/>.
+    /// </remarks>
+    internal class ActivatedValue : ObservableBase<object>, IDescription
+    {
+        /// <summary>
+        /// The activator.
+        /// </summary>
+        private readonly IObservable<bool> _activator;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ActivatedObservable"/> class.
+        /// </summary>
+        /// <param name="activator">The activator.</param>
+        /// <param name="value">The activated value.</param>
+        /// <param name="description">The binding description.</param>
+        public ActivatedValue(
+            IObservable<bool> activator,
+            object value,
+            string description)
+        {
+            _activator = activator;
+            Value = value;
+            Description = description;
+        }
+
+        /// <summary>
+        /// Gets the activated value.
+        /// </summary>
+        public object Value
+        {
+            get;
+        }
+
+        /// <summary>
+        /// Gets a description of the binding.
+        /// </summary>
+        public string Description
+        {
+            get;
+        }
+
+        /// <summary>
+        /// Notifies the provider that an observer is to receive notifications.
+        /// </summary>
+        /// <param name="observer">The observer.</param>
+        /// <returns>IDisposable object used to unsubscribe from the observable sequence.</returns>
+        protected override IDisposable SubscribeCore(IObserver<object> observer)
+        {
+            Contract.Requires<ArgumentNullException>(observer != null);
+
+            return _activator
+                .Select(active => active ? Value : PerspexProperty.UnsetValue)
+                .Subscribe(observer);
+        }
+    }
+}

+ 15 - 4
src/Perspex.Styling/Styling/Setter.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using System.Reactive.Subjects;
 using Perspex.Data;
 using Perspex.Metadata;
 
@@ -77,8 +78,9 @@ namespace Perspex.Styling
                 }
                 else
                 {
-                    throw new NotSupportedException(
-                        "Setter bindings with activators not yet supported.");
+                    var subject = binding.CreateSubject(control, Property);
+                    var activated = new ActivatedSubject(activator, subject, style.ToString());
+                    Bind(control, Property, binding, activated);
                 }
             }
             else
@@ -89,13 +91,22 @@ namespace Perspex.Styling
                 }
                 else
                 {
-                    var activated = new StyleBinding(activator, Value, style.ToString());
+                    var activated = new ActivatedValue(activator, Value, style.ToString());
                     control.Bind(Property, activated, BindingPriority.StyleTrigger);
                 }
             }
         }
 
         private void Bind(IStyleable control, PerspexProperty property, IBinding binding)
+        {
+            Bind(control, property, binding, binding.CreateSubject(control, property));
+        }
+
+        private void Bind(
+            IStyleable control, 
+            PerspexProperty property, 
+            IBinding binding, 
+            ISubject<object> subject)
         {
             var mode = binding.Mode;
 
@@ -106,7 +117,7 @@ namespace Perspex.Styling
 
             control.Bind(
                 property,
-                binding.CreateSubject(control, property),
+                subject,
                 mode,
                 binding.Priority);
         }

+ 0 - 107
src/Perspex.Styling/Styling/StyleBinding.cs

@@ -1,107 +0,0 @@
-// Copyright (c) The Perspex Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
-using System.Reactive;
-using System.Reactive.Linq;
-
-namespace Perspex.Styling
-{
-    /// <summary>
-    /// Provides an observable for a style.
-    /// </summary>
-    /// <remarks>
-    /// A <see cref="StyleBinding"/> has two inputs: an activator observable and either an
-    /// <see cref="ActivatedValue"/> or a <see cref="Source"/> observable which produces the
-    /// activated value. When the activator produces true, the <see cref="StyleBinding"/> will
-    /// produce the current activated value. When the activator produces false it will produce
-    /// <see cref="PerspexProperty.UnsetValue"/>.
-    /// </remarks>
-    internal class StyleBinding : ObservableBase<object>, IDescription
-    {
-        /// <summary>
-        /// The activator.
-        /// </summary>
-        private readonly IObservable<bool> _activator;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="StyleBinding"/> class.
-        /// </summary>
-        /// <param name="activator">The activator.</param>
-        /// <param name="activatedValue">The activated value.</param>
-        /// <param name="description">The binding description.</param>
-        public StyleBinding(
-            IObservable<bool> activator,
-            object activatedValue,
-            string description)
-        {
-            _activator = activator;
-            ActivatedValue = activatedValue;
-            Description = description;
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="StyleBinding"/> class.
-        /// </summary>
-        /// <param name="activator">The activator.</param>
-        /// <param name="source">An observable that produces the activated value.</param>
-        /// <param name="description">The binding description.</param>
-        public StyleBinding(
-            IObservable<bool> activator,
-            IObservable<object> source,
-            string description)
-        {
-            _activator = activator;
-            Description = description;
-            Source = source;
-        }
-
-        /// <summary>
-        /// Gets the activated value.
-        /// </summary>
-        public object ActivatedValue
-        {
-            get;
-        }
-
-        /// <summary>
-        /// Gets a description of the binding.
-        /// </summary>
-        public string Description
-        {
-            get;
-        }
-
-        /// <summary>
-        /// Gets an observable which produces the <see cref="ActivatedValue"/>.
-        /// </summary>
-        public IObservable<object> Source
-        {
-            get;
-        }
-
-        /// <summary>
-        /// Notifies the provider that an observer is to receive notifications.
-        /// </summary>
-        /// <param name="observer">The observer.</param>
-        /// <returns>IDisposable object used to unsubscribe from the observable sequence.</returns>
-        protected override IDisposable SubscribeCore(IObserver<object> observer)
-        {
-            Contract.Requires<ArgumentNullException>(observer != null);
-
-            if (Source == null)
-            {
-                return _activator
-                    .Select(active => active ? ActivatedValue : PerspexProperty.UnsetValue)
-                    .Subscribe(observer);
-            }
-            else
-            {
-                return _activator
-                    .CombineLatest(Source, (x, y) => new { Active = x, Value = y })
-                    .Select(x => x.Active ? x.Value : PerspexProperty.UnsetValue)
-                    .Subscribe(observer);
-            }
-        }
-    }
-}

+ 70 - 0
tests/Perspex.Styling.UnitTests/ActivatedObservableTests.cs

@@ -0,0 +1,70 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+using Xunit;
+
+namespace Perspex.Styling.UnitTests
+{
+    public class ActivatedObservableTests
+    {
+        [Fact]
+        public void Should_Produce_Correct_Values()
+        {
+            var activator = new BehaviorSubject<bool>(false);
+            var source = new BehaviorSubject<object>(1);
+            var target = new ActivatedObservable(activator, source, string.Empty);
+            var result = new List<object>();
+
+            target.Subscribe(x => result.Add(x));
+
+            activator.OnNext(true);
+            source.OnNext(2);
+            activator.OnNext(false);
+            source.OnNext(3);
+            activator.OnNext(true);
+
+            Assert.Equal(
+                new[] 
+                {
+                    PerspexProperty.UnsetValue,
+                    1,
+                    2,
+                    PerspexProperty.UnsetValue,
+                    3,
+                }, 
+                result);
+        }
+
+        [Fact]
+        public void Should_Complete_When_Source_Completes()
+        {
+            var activator = new BehaviorSubject<bool>(false);
+            var source = new BehaviorSubject<object>(1);
+            var target = new ActivatedObservable(activator, source, string.Empty);
+            var completed = false;
+
+            target.Subscribe(_ => { }, () => completed = true);
+            source.OnCompleted();
+
+            Assert.True(completed);
+        }
+
+        [Fact]
+        public void Should_Complete_When_Activator_Completes()
+        {
+            var activator = new BehaviorSubject<bool>(false);
+            var source = new BehaviorSubject<object>(1);
+            var target = new ActivatedObservable(activator, source, string.Empty);
+            var completed = false;
+
+            target.Subscribe(_ => { }, () => completed = true);
+            activator.OnCompleted();
+
+            Assert.True(completed);
+        }
+    }
+}

+ 46 - 0
tests/Perspex.Styling.UnitTests/ActivatedSubjectTests.cs

@@ -0,0 +1,46 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System.Reactive.Subjects;
+using Perspex.Data;
+using Xunit;
+
+namespace Perspex.Styling.UnitTests
+{
+    public class ActivatedSubjectTests
+    {
+        [Fact]
+        public void Should_Set_Values()
+        {
+            var data = new Class1 { Foo = "foo" };
+            var activator = new BehaviorSubject<bool>(false);
+            var source = data.GetSubject(
+                (PerspexProperty)Class1.FooProperty, 
+                BindingPriority.LocalValue);
+            var target = new ActivatedSubject(activator, source, string.Empty);
+
+            target.OnNext("bar");
+            Assert.Equal("foo", data.Foo);
+            activator.OnNext(true);
+            target.OnNext("baz");
+            Assert.Equal("baz", data.Foo);
+            activator.OnNext(false);
+            Assert.Equal("foo", data.Foo);
+            target.OnNext("bax");
+            activator.OnNext(true);
+            Assert.Equal("bax", data.Foo);
+        }
+
+        private class Class1 : PerspexObject
+        {
+            public static readonly PerspexProperty<string> FooProperty =
+                PerspexProperty.Register<Class1, string>("Foo", "foodefault");
+
+            public string Foo
+            {
+                get { return GetValue(FooProperty); }
+                set { SetValue(FooProperty, value); }
+            }
+        }
+    }
+}

+ 42 - 0
tests/Perspex.Styling.UnitTests/ActivatedValueTests.cs

@@ -0,0 +1,42 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Reactive.Linq;
+using System.Reactive.Subjects;
+using Xunit;
+
+namespace Perspex.Styling.UnitTests
+{
+    public class ActivatedValueTests
+    {
+        [Fact]
+        public void Should_Produce_Correct_Values()
+        {
+            var activator = new BehaviorSubject<bool>(false);
+            var target = new ActivatedValue(activator, 1, string.Empty);
+            var result = new List<object>();
+
+            target.Subscribe(x => result.Add(x));
+
+            activator.OnNext(true);
+            activator.OnNext(false);
+
+            Assert.Equal(new[] { PerspexProperty.UnsetValue, 1, PerspexProperty.UnsetValue }, result);
+        }
+
+        [Fact]
+        public void Should_Complete_When_Activator_Completes()
+        {
+            var activator = new BehaviorSubject<bool>(false);
+            var target = new ActivatedValue(activator, 1, string.Empty);
+            var completed = false;
+
+            target.Subscribe(_ => { }, () => completed = true);
+            activator.OnCompleted();
+
+            Assert.True(completed);
+        }
+    }
+}

+ 3 - 1
tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj

@@ -80,6 +80,8 @@
     <Otherwise />
   </Choose>
   <ItemGroup>
+    <Compile Include="ActivatedValueTests.cs" />
+    <Compile Include="ActivatedSubjectTests.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SelectorTests_Class.cs" />
     <Compile Include="SelectorTests_Child.cs" />
@@ -90,7 +92,7 @@
     <Compile Include="SelectorTests_OfType.cs" />
     <Compile Include="SelectorTests_Template.cs" />
     <Compile Include="StyleActivatorTests.cs" />
-    <Compile Include="StyleBindingTests.cs" />
+    <Compile Include="ActivatedObservableTests.cs" />
     <Compile Include="SetterTests.cs" />
     <Compile Include="StyleTests.cs" />
     <Compile Include="TestControlBase.cs" />

+ 0 - 79
tests/Perspex.Styling.UnitTests/StyleBindingTests.cs

@@ -1,79 +0,0 @@
-// Copyright (c) The Perspex Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.Reactive.Linq;
-using System.Reactive.Subjects;
-using Xunit;
-
-namespace Perspex.Styling.UnitTests
-{
-    public class StyleBindingTests
-    {
-        [Fact]
-        public async void Should_Produce_UnsetValue_On_Activator_False()
-        {
-            var activator = new BehaviorSubject<bool>(false);
-            var target = new StyleBinding(activator, 1, string.Empty);
-            var result = await target.Take(1);
-
-            Assert.Equal(PerspexProperty.UnsetValue, result);
-        }
-
-        [Fact]
-        public async void Should_Produce_Value_On_Activator_True()
-        {
-            var activator = new BehaviorSubject<bool>(true);
-            var target = new StyleBinding(activator, 1, string.Empty);
-            var result = await target.Take(1);
-
-            Assert.Equal(1, result);
-        }
-
-        [Fact]
-        public void Should_Change_Value_On_Activator_Change()
-        {
-            var activator = new BehaviorSubject<bool>(false);
-            var target = new StyleBinding(activator, 1, string.Empty);
-            var result = new List<object>();
-
-            target.Subscribe(x => result.Add(x));
-
-            activator.OnNext(true);
-            activator.OnNext(false);
-
-            Assert.Equal(new[] { PerspexProperty.UnsetValue, 1, PerspexProperty.UnsetValue }, result);
-        }
-
-        [Fact]
-        public void Should_Change_Value_With_Source_Observable()
-        {
-            var activator = new BehaviorSubject<bool>(false);
-            var source = new BehaviorSubject<object>(1);
-            var target = new StyleBinding(activator, source, string.Empty);
-            var result = new List<object>();
-
-            target.Subscribe(x => result.Add(x));
-
-            activator.OnNext(true);
-            source.OnNext(2);
-            activator.OnNext(false);
-
-            Assert.Equal(new[] { PerspexProperty.UnsetValue, 1, 2, PerspexProperty.UnsetValue }, result);
-        }
-
-        [Fact]
-        public void Should_Complete_When_Activator_Completes()
-        {
-            var activator = new BehaviorSubject<bool>(false);
-            var target = new StyleBinding(activator, 1, string.Empty);
-            var completed = false;
-
-            target.Subscribe(_ => { }, () => completed = true);
-            activator.OnCompleted();
-
-            Assert.True(completed);
-        }
-    }
-}