Browse Source

Remove ExpressionValue.

Use PerspexProperty.UnsetValue instead.
Steven Kirk 10 years ago
parent
commit
43a66901fc

+ 5 - 0
src/Markup/Perspex.Markup.Xaml/Binding/XamlBinding.cs

@@ -29,6 +29,11 @@ namespace Perspex.Markup.Xaml.Binding
 
         public void Bind(IObservablePropertyBag instance, PerspexProperty property)
         {
+            if (property == Control.DataContextProperty && instance.InheritanceParent != null)
+            {
+                instance = instance.InheritanceParent as IObservablePropertyBag ?? instance;
+            }
+
             var subject = new ExpressionSubject(CreateExpressionObserver(instance));
             Bind(instance, property, subject);
         }

+ 1 - 1
src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs

@@ -32,7 +32,7 @@ namespace Perspex.Markup.Xaml.Templates
             if (ItemsSource != null)
             {
                 var obs = new ExpressionObserver(item, ItemsSource.SourcePropertyPath);
-                return obs.Take(1).Wait().Value as IEnumerable;
+                return obs.Take(1).Wait() as IEnumerable;
             }
 
             return null;

+ 10 - 10
src/Markup/Perspex.Markup/Binding/ExpressionNode.cs

@@ -6,13 +6,13 @@ using System.Reactive.Subjects;
 
 namespace Perspex.Markup.Binding
 {
-    internal abstract class ExpressionNode : IObservable<ExpressionValue>
+    internal abstract class ExpressionNode : IObservable<object>
     {
         private object _target;
 
-        private Subject<ExpressionValue> _subject;
+        private Subject<object> _subject;
 
-        private ExpressionValue _value = ExpressionValue.None;
+        private object _value = PerspexProperty.UnsetValue;
 
         public ExpressionNode Next { get; set; }
 
@@ -34,17 +34,17 @@ namespace Perspex.Markup.Binding
                 }
                 else
                 {
-                    CurrentValue = ExpressionValue.None;
+                    CurrentValue = PerspexProperty.UnsetValue;
                 }
 
                 if (Next != null)
                 {
-                    Next.Target = CurrentValue.Value;
+                    Next.Target = CurrentValue;
                 }
             }
         }
 
-        public ExpressionValue CurrentValue
+        public object CurrentValue
         {
             get
             {
@@ -57,7 +57,7 @@ namespace Perspex.Markup.Binding
 
                 if (Next != null)
                 {
-                    Next.Target = value.Value;
+                    Next.Target = value;
                 }
 
                 if (_subject != null)
@@ -72,7 +72,7 @@ namespace Perspex.Markup.Binding
             return Next?.SetValue(value) ?? false;
         }
 
-        public virtual IDisposable Subscribe(IObserver<ExpressionValue> observer)
+        public virtual IDisposable Subscribe(IObserver<object> observer)
         {
             if (Next != null)
             {
@@ -82,7 +82,7 @@ namespace Perspex.Markup.Binding
             {
                 if (_subject == null)
                 {
-                    _subject = new Subject<ExpressionValue>();
+                    _subject = new Subject<object>();
                 }
 
                 observer.OnNext(CurrentValue);
@@ -92,7 +92,7 @@ namespace Perspex.Markup.Binding
 
         protected virtual void SubscribeAndUpdate(object target)
         {
-            CurrentValue = new ExpressionValue(target);
+            CurrentValue = target;
         }
 
         protected virtual void Unsubscribe(object target)

+ 2 - 2
src/Markup/Perspex.Markup/Binding/ExpressionObserver.cs

@@ -10,7 +10,7 @@ namespace Perspex.Markup.Binding
     /// <summary>
     /// Observes and sets the value of an expression on an object.
     /// </summary>
-    public class ExpressionObserver : ObservableBase<ExpressionValue>, IDescription
+    public class ExpressionObserver : ObservableBase<object>, IDescription
     {
         private object _root;
         private int _count;
@@ -83,7 +83,7 @@ namespace Perspex.Markup.Binding
         string IDescription.Description => Expression;
 
         /// <inheritdoc/>
-        protected override IDisposable SubscribeCore(IObserver<ExpressionValue> observer)
+        protected override IDisposable SubscribeCore(IObserver<object> observer)
         {
             IncrementCount();
 

+ 1 - 1
src/Markup/Perspex.Markup/Binding/ExpressionSubject.cs

@@ -45,7 +45,7 @@ namespace Perspex.Markup.Binding
         /// <inheritdoc/>
         public IDisposable Subscribe(IObserver<object> observer)
         {
-            return _inner.Select(x => x.Value).Subscribe(observer);
+            return _inner.Subscribe(observer);
         }
     }
 }

+ 0 - 38
src/Markup/Perspex.Markup/Binding/ExpressionValue.cs

@@ -1,38 +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;
-
-namespace Perspex.Markup.Binding
-{
-    /// <summary>
-    /// Holds the value for an <see cref="ExpressionObserver"/>.
-    /// </summary>
-    public struct ExpressionValue
-    {
-        /// <summary>
-        /// An <see cref="ExpressionValue"/> that has no value.
-        /// </summary>
-        public static readonly ExpressionValue None = new ExpressionValue();
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ExpressionValue"/> struct.
-        /// </summary>
-        /// <param name="value"></param>
-        public ExpressionValue(object value)
-        {
-            HasValue = true;
-            Value = value;
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether the evaluated expression resulted in a value.
-        /// </summary>
-        public bool HasValue { get; }
-
-        /// <summary>
-        /// Gets a the result of the expression.
-        /// </summary>
-        public object Value { get; }
-    }
-}

+ 4 - 4
src/Markup/Perspex.Markup/Binding/IndexerNode.cs

@@ -83,24 +83,24 @@ namespace Perspex.Markup.Binding
             }
         }
 
-        private ExpressionValue GetValue(object target)
+        private object GetValue(object target)
         {
             var typeInfo = target.GetType().GetTypeInfo();
             var list = target as IList;
 
             if (typeInfo.IsArray && _intArgs != null)
             {
-                return new ExpressionValue(((Array)target).GetValue(_intArgs));
+                return ((Array)target).GetValue(_intArgs);
             }
             else if (target is IList && _intArgs?.Length == 1)
             {
                 if (_intArgs[0] < list.Count)
                 {
-                    return new ExpressionValue(list[_intArgs[0]]);
+                    return list[_intArgs[0]];
                 }
             }
 
-            return ExpressionValue.None;
+            return PerspexProperty.UnsetValue;
         }
     }
 }

+ 6 - 6
src/Markup/Perspex.Markup/Binding/LogicalNotNode.cs

@@ -14,19 +14,19 @@ namespace Perspex.Markup.Binding
             throw new NotSupportedException("Cannot set a negated binding.");
         }
 
-        public override IDisposable Subscribe(IObserver<ExpressionValue> observer)
+        public override IDisposable Subscribe(IObserver<object> observer)
         {
             return Next.Select(x => Negate(x)).Subscribe(observer);
         }
 
-        private ExpressionValue Negate(ExpressionValue v)
+        private object Negate(object v)
         {
-            if (v.HasValue)
+            if (v != PerspexProperty.UnsetValue)
             {
                 try
                 {
-                    var boolean = Convert.ToBoolean(v.Value, CultureInfo.InvariantCulture);
-                    return new ExpressionValue(!boolean);
+                    var boolean = Convert.ToBoolean(v, CultureInfo.InvariantCulture);
+                    return !boolean;
                 }
                 catch
                 {
@@ -34,7 +34,7 @@ namespace Perspex.Markup.Binding
                 }
             }
 
-            return ExpressionValue.None;
+            return PerspexProperty.UnsetValue;
         }
     }
 }

+ 7 - 7
src/Markup/Perspex.Markup/Binding/PropertyAccessorNode.cs

@@ -69,7 +69,7 @@ namespace Perspex.Markup.Binding
 
             if (!set)
             {
-                CurrentValue = ExpressionValue.None;
+                CurrentValue = PerspexProperty.UnsetValue;
             }
         }
 
@@ -115,11 +115,11 @@ namespace Perspex.Markup.Binding
             // ReactiveCommand is an IObservable but we want to bind to it, not its value.
             if (observable != null && command == null)
             {
-                CurrentValue = ExpressionValue.None;
+                CurrentValue = PerspexProperty.UnsetValue;
                 set = true;
                 _subscription = observable
                     .ObserveOn(SynchronizationContext.Current)
-                    .Subscribe(x => CurrentValue = new ExpressionValue(x));
+                    .Subscribe(x => CurrentValue = x);
             }
             else if (task != null)
             {
@@ -129,13 +129,13 @@ namespace Perspex.Markup.Binding
                 {
                     if (task.Status == TaskStatus.RanToCompletion)
                     {
-                        CurrentValue = new ExpressionValue(resultProperty.GetValue(task));
+                        CurrentValue = resultProperty.GetValue(task);
                         set = true;
                     }
                     else
                     {
                         task.ContinueWith(
-                                x => CurrentValue = new ExpressionValue(resultProperty.GetValue(task)),
+                                x => CurrentValue = resultProperty.GetValue(task),
                                 TaskScheduler.FromCurrentSynchronizationContext())
                             .ConfigureAwait(false);
                     }
@@ -143,13 +143,13 @@ namespace Perspex.Markup.Binding
             }
             else
             {
-                CurrentValue = new ExpressionValue(value);
+                CurrentValue = value;
                 set = true;
             }
 
             if (!set)
             {
-                CurrentValue = ExpressionValue.None;
+                CurrentValue = PerspexProperty.UnsetValue;
             }
         }
 

+ 0 - 1
src/Markup/Perspex.Markup/Perspex.Markup.csproj

@@ -38,7 +38,6 @@
     <Compile Include="Binding\ExpressionNodeBuilder.cs" />
     <Compile Include="Binding\ExpressionParseException.cs" />
     <Compile Include="Binding\ExpressionSubject.cs" />
-    <Compile Include="Binding\ExpressionValue.cs" />
     <Compile Include="Binding\LogicalNotNode.cs" />
     <Compile Include="Binding\IndexerNode.cs" />
     <Compile Include="Binding\Parsers\ArgumentListParser.cs" />

+ 5 - 0
src/Perspex.Base/IPropertyBag.cs

@@ -8,6 +8,11 @@ namespace Perspex
     /// </summary>
     public interface IPropertyBag
     {
+        /// <summary>
+        /// Gets the object that inherited <see cref="PerspexProperty"/> values are inherited from.
+        /// </summary>
+        IPropertyBag InheritanceParent { get; }
+
         /// <summary>
         /// Clears a <see cref="PerspexProperty"/>'s local value.
         /// </summary>

+ 5 - 0
src/Perspex.Base/PerspexObject.cs

@@ -100,6 +100,11 @@ namespace Perspex
             remove { _inpcChanged -= value; }
         }
 
+        /// <summary>
+        /// Gets the object that inherited <see cref="PerspexProperty"/> values are inherited from.
+        /// </summary>
+        IPropertyBag IPropertyBag.InheritanceParent => InheritanceParent;
+
         /// <summary>
         /// Gets or sets the parent object that inherited <see cref="PerspexProperty"/> values
         /// are inherited from.

+ 10 - 13
tests/Perspex.Markup.UnitTests/Binding/ExpressionObserverTests_Indexer.cs

@@ -19,8 +19,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[1]");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal("bar", result.Value);
+            Assert.Equal("bar", result);
         }
 
         [Fact]
@@ -30,8 +29,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[1, 1]");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal("qux", result.Value);
+            Assert.Equal("qux", result);
         }
 
         [Fact]
@@ -41,8 +39,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[1]");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal("bar", result.Value);
+            Assert.Equal("bar", result);
         }
 
         [Fact]
@@ -52,10 +49,10 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[2]");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             data.Foo.Add("baz");
 
-            Assert.Equal(new[] { null, "baz" }, result);
+            Assert.Equal(new[] { PerspexProperty.UnsetValue, "baz" }, result);
         }
 
         [Fact]
@@ -65,7 +62,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[0]");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             data.Foo.RemoveAt(0);
 
             Assert.Equal(new[] { "foo", "bar" }, result);
@@ -78,7 +75,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[1]");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             data.Foo[1] = "baz";
 
             Assert.Equal(new[] { "bar", "baz" }, result);
@@ -91,7 +88,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[1]");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             data.Foo.Move(0, 1);
 
             Assert.Equal(new[] { "bar", "foo" }, result);
@@ -104,10 +101,10 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo[1]");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             data.Foo.Clear();
 
-            Assert.Equal(new[] { "bar", null }, result);
+            Assert.Equal(new[] { "bar", PerspexProperty.UnsetValue }, result);
         }
     }
 }

+ 7 - 12
tests/Perspex.Markup.UnitTests/Binding/ExpressionObserverTests_Negation.cs

@@ -17,8 +17,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "!Foo");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal(false, result.Value);
+            Assert.Equal(false, result);
         }
 
         [Fact]
@@ -28,8 +27,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "!Foo");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal(true, result.Value);
+            Assert.Equal(true, result);
         }
 
         [Fact]
@@ -39,8 +37,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "!Foo");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal(false, result.Value);
+            Assert.Equal(false, result);
         }
 
         [Fact]
@@ -50,8 +47,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "!Foo");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal(true, result.Value);
+            Assert.Equal(true, result);
         }
 
         [Fact]
@@ -61,8 +57,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "!Foo");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal(false, result.Value);
+            Assert.Equal(false, result);
         }
 
         [Fact]
@@ -72,7 +67,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "!Foo");
             var result = await target.Take(1);
 
-            Assert.False(result.HasValue);
+            Assert.Equal(PerspexProperty.UnsetValue, result);
         }
 
         [Fact]
@@ -82,7 +77,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "!Foo");
             var result = await target.Take(1);
 
-            Assert.False(result.HasValue);
+            Assert.Equal(PerspexProperty.UnsetValue, result);
         }
 
         [Fact]

+ 4 - 4
tests/Perspex.Markup.UnitTests/Binding/ExpressionObserverTests_Observable.cs

@@ -22,11 +22,11 @@ namespace Perspex.Markup.UnitTests.Binding
                 var target = new ExpressionObserver(data, "Foo");
                 var result = new List<object>();
 
-                var sub = target.Subscribe(x => result.Add(x.Value));
+                var sub = target.Subscribe(x => result.Add(x));
                 source.OnNext("bar");
                 sync.ExecutePostedCallbacks();
 
-                Assert.Equal(new[] { null, "foo", "bar" }, result);
+                Assert.Equal(new[] { PerspexProperty.UnsetValue, "foo", "bar" }, result);
             }
         }
 
@@ -39,11 +39,11 @@ namespace Perspex.Markup.UnitTests.Binding
                 var target = new ExpressionObserver(data, "Next.Foo");
                 var result = new List<object>();
 
-                var sub = target.Subscribe(x => result.Add(x.Value));
+                var sub = target.Subscribe(x => result.Add(x));
                 data.Next.OnNext(new Class2("foo"));
                 sync.ExecutePostedCallbacks();
 
-                Assert.Equal(new[] { null, "foo" }, result);
+                Assert.Equal(new[] { PerspexProperty.UnsetValue, "foo" }, result);
 
                 sub.Dispose();
                 Assert.Equal(0, data.SubscriptionCount);

+ 14 - 17
tests/Perspex.Markup.UnitTests/Binding/ExpressionObserverTests_Property.cs

@@ -18,8 +18,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal("foo", result.Value);
+            Assert.Equal("foo", result);
         }
 
         [Fact]
@@ -29,8 +28,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal("foo", result.Value);
+            Assert.Equal("foo", result);
         }
 
         [Fact]
@@ -40,8 +38,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo.Bar.Baz");
             var result = await target.Take(1);
 
-            Assert.True(result.HasValue);
-            Assert.Equal("baz", result.Value);
+            Assert.Equal("baz", result);
         }
 
         [Fact]
@@ -51,7 +48,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo.Bar.Baz");
             var result = await target.Take(1);
 
-            Assert.False(result.HasValue);
+            Assert.Equal(PerspexProperty.UnsetValue, result);
         }
 
         [Fact]
@@ -61,7 +58,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Foo");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             data.Foo = "bar";
 
             Assert.Equal(new[] { "foo", "bar" }, result);
@@ -78,7 +75,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Next.Bar");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             ((Class2)data.Next).Bar = "baz";
 
             Assert.Equal(new[] { "bar", "baz" }, result);
@@ -96,7 +93,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Next.Bar");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             var old = data.Next;
             data.Next = new Class2 { Bar = "baz" };
 
@@ -116,12 +113,12 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Next.Bar");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             var old = data.Next;
             data.Next = null;
             data.Next = new Class2 { Bar = "baz" };
 
-            Assert.Equal(new[] { "bar", null, "baz" }, result);
+            Assert.Equal(new[] { "bar", PerspexProperty.UnsetValue, "baz" }, result);
 
             sub.Dispose();
 
@@ -137,13 +134,13 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(data, "Next.Bar");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             var old = data.Next;
             var breaking = new WithoutBar();
             data.Next = breaking;
             data.Next = new Class2 { Bar = "baz" };
 
-            Assert.Equal(new[] { "bar", null, "baz" }, result);
+            Assert.Equal(new[] { "bar", PerspexProperty.UnsetValue, "baz" }, result);
 
             sub.Dispose();
 
@@ -206,7 +203,7 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(null, "Foo");
             var result = await target.Take(1);
 
-            Assert.False(result.HasValue);
+            Assert.Equal(PerspexProperty.UnsetValue, result);
         }
 
         [Fact]
@@ -217,11 +214,11 @@ namespace Perspex.Markup.UnitTests.Binding
             var target = new ExpressionObserver(first, "Foo");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x.Value));
+            var sub = target.Subscribe(x => result.Add(x));
             target.Root = second;
             target.Root = null;
 
-            Assert.Equal(new[] { "foo", "bar", null }, result);
+            Assert.Equal(new[] { "foo", "bar", PerspexProperty.UnsetValue }, result);
 
             Assert.Equal(0, first.SubscriptionCount);
             Assert.Equal(0, second.SubscriptionCount);

+ 5 - 5
tests/Perspex.Markup.UnitTests/Binding/ExpressionObserverTests_Task.cs

@@ -23,11 +23,11 @@ namespace Perspex.Markup.UnitTests.Binding
                 var target = new ExpressionObserver(data, "Foo");
                 var result = new List<object>();
 
-                var sub = target.Subscribe(x => result.Add(x.Value));
+                var sub = target.Subscribe(x => result.Add(x));
                 tcs.SetResult("foo");
                 sync.ExecutePostedCallbacks();
 
-                Assert.Equal(new object[] { null, "foo" }, result.ToArray());
+                Assert.Equal(new object[] { PerspexProperty.UnsetValue, "foo" }, result.ToArray());
             }
         }
 
@@ -40,7 +40,7 @@ namespace Perspex.Markup.UnitTests.Binding
                 var target = new ExpressionObserver(data, "Foo");
                 var result = new List<object>();
 
-                var sub = target.Subscribe(x => result.Add(x.Value));
+                var sub = target.Subscribe(x => result.Add(x));
 
                 Assert.Equal(new object[] { "foo" }, result.ToArray());
             }
@@ -56,11 +56,11 @@ namespace Perspex.Markup.UnitTests.Binding
                 var target = new ExpressionObserver(data, "Next.Foo");
                 var result = new List<object>();
 
-                var sub = target.Subscribe(x => result.Add(x.Value));
+                var sub = target.Subscribe(x => result.Add(x));
                 tcs.SetResult(new Class2("foo"));
                 sync.ExecutePostedCallbacks();
 
-                Assert.Equal(new object[] { null, "foo" }, result.ToArray());
+                Assert.Equal(new object[] { PerspexProperty.UnsetValue, "foo" }, result.ToArray());
             }
         }
 

+ 8 - 0
tests/Perspex.Styling.UnitTests/SelectorTests_Child.cs

@@ -88,6 +88,14 @@ namespace Perspex.Styling.UnitTests
 
             public ITemplatedControl TemplatedParent { get; }
 
+            public IPropertyBag InheritanceParent
+            {
+                get
+                {
+                    throw new NotImplementedException();
+                }
+            }
+
             public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
             {
                 throw new NotImplementedException();

+ 8 - 0
tests/Perspex.Styling.UnitTests/SelectorTests_Descendent.cs

@@ -120,6 +120,14 @@ namespace Perspex.Styling.UnitTests
 
             public ITemplatedControl TemplatedParent { get; }
 
+            public IPropertyBag InheritanceParent
+            {
+                get
+                {
+                    throw new NotImplementedException();
+                }
+            }
+
             public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
             {
                 throw new NotImplementedException();

+ 8 - 0
tests/Perspex.Styling.UnitTests/TestControlBase.cs

@@ -28,6 +28,14 @@ namespace Perspex.Styling.UnitTests
             set;
         }
 
+        public IPropertyBag InheritanceParent
+        {
+            get
+            {
+                throw new NotImplementedException();
+            }
+        }
+
         public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
         {
             throw new NotImplementedException();

+ 8 - 0
tests/Perspex.Styling.UnitTests/TestTemplatedControl.cs

@@ -34,6 +34,14 @@ namespace Perspex.Styling.UnitTests
             get;
         }
 
+        public IPropertyBag InheritanceParent
+        {
+            get
+            {
+                throw new NotImplementedException();
+            }
+        }
+
         public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
         {
             throw new NotImplementedException();