Browse Source

All tests now passing.

Steven Kirk 9 years ago
parent
commit
89dc27f276

+ 6 - 6
src/Perspex.Base/AttachedProperty.cs

@@ -16,14 +16,14 @@ namespace Perspex
         /// </summary>
         /// <param name="name">The name of the property.</param>
         /// <param name="ownerType">The class that is registering the property.</param>
-        /// <param name="inherits">Whether the property inherits its value.</param>
         /// <param name="metadata">The property metadata.</param>
+        /// <param name="inherits">Whether the property inherits its value.</param>
         public AttachedProperty(
             string name,
-            Type ownerType,
-            bool inherits,
-            StyledPropertyMetadata metadata)
-            : base(name, ownerType, inherits, metadata)
+            Type ownerType,            
+            StyledPropertyMetadata<TValue> metadata,
+            bool inherits = false)
+            : base(name, ownerType, metadata, inherits)
         {
         }
 
@@ -35,7 +35,7 @@ namespace Perspex
         /// </summary>
         /// <typeparam name="TOwner">The owner type.</typeparam>
         /// <returns>The property.</returns>
-        public StyledProperty<TValue> AddOwner<TOwner>()
+        public StyledProperty<TValue> AddOwner<TOwner>() where TOwner : IPerspexObject
         {
             var result = new StyledProperty<TValue>(this, typeof(TOwner));
             PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result);

+ 1 - 1
src/Perspex.Base/DirectProperty.cs

@@ -85,7 +85,7 @@ namespace Perspex
                 getter,
                 setter);
 
-            PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result);
+            PerspexPropertyRegistry.Instance.Register(typeof(TNewOwner), result);
             return result;
         }
 

+ 23 - 0
src/Perspex.Base/IStyledPropertyMetadata.cs

@@ -0,0 +1,23 @@
+// 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
+{
+    /// <summary>
+    /// Untyped interface to <see cref="StyledPropertyMetadata{TValue}"/>
+    /// </summary>
+    public interface IStyledPropertyMetadata
+    {
+        /// <summary>
+        /// Gets the default value for the property.
+        /// </summary>
+        object DefaultValue { get; }
+
+        /// <summary>
+        /// Gets the property's validation function.
+        /// </summary>
+        Func<IPerspexObject, object, object> Validate { get; }
+    }
+}

+ 2 - 1
src/Perspex.Base/Perspex.Base.csproj

@@ -53,6 +53,7 @@
     <Compile Include="IDirectPropertyAccessor.cs" />
     <Compile Include="DirectProperty.cs" />
     <Compile Include="IPerspexObject.cs" />
+    <Compile Include="IStyledPropertyMetadata.cs" />
     <Compile Include="Metadata\ContentAttribute.cs" />
     <Compile Include="PerspexDisposable.cs" />
     <Compile Include="PerspexLocator.cs" />
@@ -86,7 +87,7 @@
     <Compile Include="Reactive\AnonymousSubject`1.cs" />
     <Compile Include="Reactive\AnonymousSubject`2.cs" />
     <Compile Include="Reactive\PerspexObservable.cs" />
-    <Compile Include="StyledPropertyMetadata.cs" />
+    <Compile Include="StyledPropertyMetadata`1.cs" />
     <Compile Include="Threading\Dispatcher.cs" />
     <Compile Include="Threading\DispatcherPriority.cs" />
     <Compile Include="Threading\DispatcherTimer.cs" />

+ 43 - 37
src/Perspex.Base/PerspexProperty.cs

@@ -3,6 +3,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Reactive.Subjects;
 using System.Reflection;
 using Perspex.Data;
@@ -34,11 +35,13 @@ namespace Perspex
         /// <param name="valueType">The type of the property's value.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
         /// <param name="metadata">The property metadata.</param>
+        /// <param name="notifying">A <see cref="Notifying"/> callback.</param>
         protected PerspexProperty(
             string name,
             Type valueType,
             Type ownerType,
-            PropertyMetadata metadata)
+            PropertyMetadata metadata,
+            Action<IPerspexObject, bool> notifying = null)
         {
             Contract.Requires<ArgumentNullException>(name != null);
             Contract.Requires<ArgumentNullException>(valueType != null);
@@ -57,6 +60,7 @@ namespace Perspex
             Name = name;
             PropertyType = valueType;
             OwnerType = ownerType;
+            Notifying = notifying;
             _id = s_nextId++;
 
             _metadata.Add(ownerType, metadata);
@@ -75,13 +79,14 @@ namespace Perspex
 
             _initialized = source._initialized;
             _changed = source._changed;
-            _metadata = source._metadata;
+            _metadata = new Dictionary<Type, PropertyMetadata>();
 
             Name = source.Name;
             PropertyType = source.PropertyType;
             OwnerType = ownerType;
-            Notifying = Notifying;
+            Notifying = source.Notifying;
             _id = source._id;
+            _defaultMetadata = source._defaultMetadata;
         }
 
         /// <summary>
@@ -146,14 +151,18 @@ namespace Perspex
         public IObservable<PerspexPropertyChangedEventArgs> Changed => _changed;
 
         /// <summary>
-        /// The notifying callback.
+        /// Gets a method that gets called before and after the property starts being notified on an
+        /// object.
         /// </summary>
         /// <remarks>
-        /// This is a method that gets called before and after the property starts being notified
-        /// on an object; the bool argument will be true before and false afterwards. This 
-        /// callback is intended to support IsDataContextChanging.
+        /// When a property changes, change notifications are sent to all property subscribers; 
+        /// for example via the <see cref="PerspexProperty.Changed"/> observable and and the 
+        /// <see cref="PerspexObject.PropertyChanged"/> event. If this callback is set for a property,
+        /// then it will be called before and after these notifications take place. The bool argument
+        /// will be true before the property change notifications are sent and false afterwards. This 
+        /// callback is intended to support Control.IsDataContextChanging.
         /// </remarks>
-        public Action<PerspexObject, bool> Notifying { get; }
+        public Action<IPerspexObject, bool> Notifying { get; }
 
         /// <summary>
         /// Provides access to a property's binding via the <see cref="PerspexObject"/>
@@ -245,13 +254,17 @@ namespace Perspex
         {
             Contract.Requires<ArgumentNullException>(name != null);
 
-            var metadata = new StyledPropertyMetadata(
+            var metadata = new StyledPropertyMetadata<TValue>(
                 defaultValue,
                 validate: Cast(validate),
-                defaultBindingMode: defaultBindingMode,
-                notifyingCallback: notifying);
+                defaultBindingMode: defaultBindingMode);
 
-            var result = new StyledProperty<TValue>(name, typeof(TOwner), inherits, metadata);
+            var result = new StyledProperty<TValue>(
+                name, 
+                typeof(TOwner), 
+                metadata,
+                inherits,
+                notifying);
             PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result);
             return result;
         }
@@ -278,12 +291,12 @@ namespace Perspex
         {
             Contract.Requires<ArgumentNullException>(name != null);
 
-            var metadata = new StyledPropertyMetadata(
+            var metadata = new StyledPropertyMetadata<TValue>(
                 defaultValue,
                 validate: Cast(validate),
                 defaultBindingMode: defaultBindingMode);
 
-            var result = new AttachedProperty<TValue>(name, typeof(TOwner), inherits, metadata);
+            var result = new AttachedProperty<TValue>(name, typeof(TOwner), metadata, inherits);
             PerspexPropertyRegistry.Instance.Register(typeof(THost), result);
             return result;
         }
@@ -311,12 +324,12 @@ namespace Perspex
         {
             Contract.Requires<ArgumentNullException>(name != null);
 
-            var metadata = new StyledPropertyMetadata(
+            var metadata = new StyledPropertyMetadata<TValue>(
                 defaultValue,
                 validate: Cast(validate),
                 defaultBindingMode: defaultBindingMode);
 
-            var result = new AttachedProperty<TValue>(name, ownerType, inherits, metadata);
+            var result = new AttachedProperty<TValue>(name, ownerType, metadata, inherits);
             PerspexPropertyRegistry.Instance.Register(typeof(THost), result);
             return result;
         }
@@ -468,27 +481,6 @@ namespace Perspex
             _changed.OnNext(e);
         }
 
-        /// <summary>
-        /// Casts a validation function accepting a typed owner to one accepting an
-        /// <see cref="IPerspexObject"/>.
-        /// </summary>
-        /// <typeparam name="TOwner">The owner type.</typeparam>
-        /// <typeparam name="TValue">The property value type.</typeparam>
-        /// <param name="f">The typed function.</param>
-        /// <returns>The untyped function.</returns>
-        protected static Func<IPerspexObject, object, object> Cast<TOwner, TValue>(Func<TOwner, TValue, TValue> f)
-            where TOwner : IPerspexObject
-        {
-            if (f == null)
-            {
-                return null;
-            }
-            else
-            {
-                return (o, v) => f((TOwner)o, (TValue)v);
-            }
-        }
-
         /// <summary>
         /// Overrides the metadata for the property on the specified type.
         /// </summary>
@@ -510,6 +502,20 @@ namespace Perspex
             _metadata.Add(type, metadata);
         }
 
+        [DebuggerHidden]
+        private static Func<IPerspexObject, TValue, TValue> Cast<TOwner, TValue>(Func<TOwner, TValue, TValue> f)
+            where TOwner : IPerspexObject
+        {
+            if (f != null)
+            {
+                return (o, v) => (o is TOwner) ? f((TOwner)o, v) : v;
+            }
+            else
+            {
+                return null;
+            }
+        }
+
         /// <summary>
         /// Class representing the <see cref="UnsetValue"/>.
         /// </summary>

+ 4 - 6
src/Perspex.Base/PerspexProperty`1.cs

@@ -17,15 +17,13 @@ namespace Perspex
         /// <param name="name">The name of the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
         /// <param name="metadata">The property metadata.</param>
+        /// <param name="notifying">A <see cref="PerspexProperty.Notifying"/> callback.</param>
         protected PerspexProperty(
             string name,
             Type ownerType,
-            PropertyMetadata metadata)
-            : base(
-                name,
-                typeof(TValue),
-                ownerType,
-                metadata)
+            PropertyMetadata metadata,
+            Action<IPerspexObject, bool> notifying = null)
+            : base(name, typeof(TValue), ownerType, metadata, notifying)
         {
         }
 

+ 1 - 24
src/Perspex.Base/PropertyMetadata.cs

@@ -15,13 +15,9 @@ namespace Perspex
         /// Initializes a new instance of the <see cref="PropertyMetadata"/> class.
         /// </summary>
         /// <param name="defaultBindingMode">The default binding mode.</param>
-        /// <param name="notifyingCallback">The property notifying callback.</param>
-        public PropertyMetadata(
-            BindingMode defaultBindingMode = BindingMode.Default,
-            Action<PerspexObject, bool> notifyingCallback = null)
+        public PropertyMetadata(BindingMode defaultBindingMode = BindingMode.Default)
         {
             DefaultBindingMode = defaultBindingMode;
-            NotifyingCallback = notifyingCallback;
         }
 
         /// <summary>
@@ -29,20 +25,6 @@ namespace Perspex
         /// </summary>
         public BindingMode DefaultBindingMode { get; private set; }
 
-        /// <summary>
-        /// Gets a method that gets called before and after the property starts being notified on an
-        /// object.
-        /// </summary>
-        /// <remarks>
-        /// When a property changes, change notifications are sent to all property subscribers; 
-        /// for example via the <see cref="PerspexProperty.Changed"/> observable and and the 
-        /// <see cref="PerspexObject.PropertyChanged"/> event. If this callback is set for a property,
-        /// then it will be called before and after these notifications take place. The bool argument
-        /// will be true before the property change notifications are sent and false afterwards. This 
-        /// callback is intended to support Control.IsDataContextChanging.
-        /// </remarks>
-        public Action<PerspexObject, bool> NotifyingCallback { get; private set; }
-
         /// <summary>
         /// Merges the metadata with the base metadata.
         /// </summary>
@@ -56,11 +38,6 @@ namespace Perspex
             {
                 DefaultBindingMode = baseMetadata.DefaultBindingMode;
             }
-
-            if (NotifyingCallback == null)
-            {
-                NotifyingCallback = baseMetadata.NotifyingCallback;
-            }
         }
     }
 }

+ 7 - 5
src/Perspex.Base/StyledProperty.cs

@@ -15,14 +15,16 @@ namespace Perspex
         /// </summary>
         /// <param name="name">The name of the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
-        /// <param name="inherits">Whether the property inherits its value.</param>
         /// <param name="metadata">The property metadata.</param>
+        /// <param name="inherits">Whether the property inherits its value.</param>
+        /// <param name="notifying">A <see cref="PerspexProperty.Notifying"/> callback.</param>
         public StyledProperty(
             string name,
             Type ownerType,
-            bool inherits,
-            StyledPropertyMetadata metadata)
-                : base(name, ownerType, inherits, metadata)
+            StyledPropertyMetadata<TValue> metadata,
+            bool inherits = false,
+            Action<IPerspexObject, bool> notifying = null)
+            : base(name, ownerType, metadata, inherits, notifying)
         {
         }
 
@@ -41,7 +43,7 @@ namespace Perspex
         /// </summary>
         /// <typeparam name="TOwner">The type of the additional owner.</typeparam>
         /// <returns>The property.</returns>        
-        public StyledProperty<TValue> AddOwner<TOwner>()
+        public StyledProperty<TValue> AddOwner<TOwner>() where TOwner : IPerspexObject
         {
             PerspexPropertyRegistry.Instance.Register(typeof(TOwner), this);
             return this;

+ 49 - 85
src/Perspex.Base/StyledPropertyBase.cs

@@ -2,8 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
-using System.Reflection;
-using Perspex.Utilities;
+using System.Diagnostics;
 
 namespace Perspex
 {
@@ -19,14 +18,16 @@ namespace Perspex
         /// </summary>
         /// <param name="name">The name of the property.</param>
         /// <param name="ownerType">The type of the class that registers the property.</param>
-        /// <param name="inherits">Whether the property inherits its value.</param>
         /// <param name="metadata">The property metadata.</param>
+        /// <param name="inherits">Whether the property inherits its value.</param>
+        /// <param name="notifying">A <see cref="PerspexProperty.Notifying"/> callback.</param>
         protected StyledPropertyBase(
             string name,
-            Type ownerType,
-            bool inherits,
-            StyledPropertyMetadata metadata)
-                : base(name, ownerType, CheckMetadata(metadata))
+            Type ownerType,            
+            StyledPropertyMetadata<TValue> metadata,
+            bool inherits = false,
+            Action<IPerspexObject, bool> notifying = null)
+                : base(name, ownerType, metadata, notifying)
         {
             Contract.Requires<ArgumentNullException>(name != null);
             Contract.Requires<ArgumentNullException>(ownerType != null);
@@ -67,34 +68,19 @@ namespace Perspex
         {
             Contract.Requires<ArgumentNullException>(type != null);
 
-            return (TValue)(GetMetadata(type) as StyledPropertyMetadata)?.DefaultValue;
+            return GetMetadata(type).DefaultValue;
         }
 
         /// <summary>
-        /// Gets the validation function for the property on the specified type.
+        /// Gets the property metadata for the specified type.
         /// </summary>
         /// <param name="type">The type.</param>
         /// <returns>
-        /// The validation function, or null if no validation function registered for this type.
+        /// The property metadata.
         /// </returns>
-        public Func<IPerspexObject, TValue, TValue> GetValidationFunc(Type type)
+        public new StyledPropertyMetadata<TValue> GetMetadata(Type type)
         {
-            return null;
-            ////Contract.Requires<ArgumentNullException>(type != null);
-
-            ////while (type != null)
-            ////{
-            ////    Func<IPerspexObject, TValue, TValue> result;
-
-            ////    if (_validation.TryGetValue(type, out result))
-            ////    {
-            ////        return result;
-            ////    }
-
-            ////    type = type.GetTypeInfo().BaseType;
-            ////}
-
-            ////return null;
+            return (StyledPropertyMetadata<TValue>)base.GetMetadata(type);
         }
 
         /// <summary>
@@ -114,44 +100,51 @@ namespace Perspex
         /// <param name="defaultValue">The default value.</param>
         public void OverrideDefaultValue(Type type, TValue defaultValue)
         {
-            OverrideMetadata(type, new StyledPropertyMetadata(defaultValue));
+            OverrideMetadata(type, new StyledPropertyMetadata<TValue>(defaultValue));
         }
 
         /// <summary>
-        /// Overrides the validation function for the property on the specified type.
+        /// Overrides the metadata for the property on the specified type.
         /// </summary>
         /// <typeparam name="T">The type.</typeparam>
-        /// <param name="validation">The validation function.</param>
-        public void OverrideValidation<T>(Func<T, TValue, TValue> validation)
-            where T : IPerspexObject
+        /// <param name="metadata">The metadata.</param>
+        public void OverrideMetadata<T>(StyledPropertyMetadata<TValue> metadata) where T : IPerspexObject
         {
-            throw new NotImplementedException();
-            ////var type = typeof(T);
-
-            ////if (_validation.ContainsKey(type))
-            ////{
-            ////    throw new InvalidOperationException("Validation is already set for this property.");
-            ////}
-
-            ////_validation.Add(type, Cast(validation));
+            base.OverrideMetadata(typeof(T), metadata);
         }
 
         /// <summary>
-        /// Overrides the validation function for the property on the specified type.
+        /// Overrides the metadata for the property on the specified type.
         /// </summary>
         /// <param name="type">The type.</param>
-        /// <param name="validation">The validation function.</param>
-        public void OverrideValidation(Type type, Func<IPerspexObject, TValue, TValue> validation)
+        /// <param name="metadata">The metadata.</param>
+        public void OverrideMetadata(Type type, StyledPropertyMetadata<TValue> metadata)
         {
-            throw new NotImplementedException();
-            //Contract.Requires<ArgumentNullException>(type != null);
+            base.OverrideMetadata(type, metadata);
+        }
+
+        /// <summary>
+        /// Overrides the validation function for the specified type.
+        /// </summary>
+        /// <typeparam name="THost">The type.</typeparam>
+        /// <param name="validate">The validation function.</param>
+        public void OverrideValidation<THost>(Func<THost, TValue, TValue> validate)
+            where THost : IPerspexObject
+        {
+            Func<IPerspexObject, TValue, TValue> f;
 
-            //if (_validation.ContainsKey(type))
-            //{
-            //    throw new InvalidOperationException("Validation is already set for this property.");
-            //}
+            if (validate != null)
+            {
+                f = Cast(validate);
+            }
+            else
+            {
+                // Passing null to the validation function means that the property metadata merge
+                // will take the base validation function, so instead use an empty validation.
+                f = (o, v) => v;
+            }
 
-            //_validation.Add(type, validation);
+            base.OverrideMetadata(typeof(THost), new StyledPropertyMetadata<TValue>(validate: f));
         }
 
         /// <summary>
@@ -166,46 +159,17 @@ namespace Perspex
         /// <inheritdoc/>
         Func<IPerspexObject, object, object> IStyledPropertyAccessor.GetValidationFunc(Type type)
         {
-            var typed = GetValidationFunc(type);
-
-            if (typed != null)
-            {
-                return (o, v) => typed(o, (TValue)v);
-            }
-            else
-            {
-                return null;
-            }
+            Contract.Requires<ArgumentNullException>(type != null);
+            return ((IStyledPropertyMetadata)base.GetMetadata(type)).Validate;
         }
 
         /// <inheritdoc/>
         object IStyledPropertyAccessor.GetDefaultValue(Type type) => GetDefaultValue(type);
 
-        private static PropertyMetadata CheckMetadata(StyledPropertyMetadata metadata)
+        [DebuggerHidden]
+        private Func<IPerspexObject, TValue, TValue> Cast<THost>(Func<THost, TValue, TValue> validate)
         {
-            var valueType = typeof(TValue).GetTypeInfo();
-
-            if (metadata.DefaultValue != null)
-            {
-                var defaultType = metadata.DefaultValue.GetType().GetTypeInfo();
-
-                if (!valueType.IsAssignableFrom(defaultType))
-                {
-                    throw new ArgumentException(
-                        "Invalid default property value. " +
-                        $"Expected {typeof(TValue)} but recieved {metadata.DefaultValue.GetType()}.");
-                }
-            }
-            else
-            {
-                if (!TypeUtilities.AcceptsNull(typeof(TValue)))
-                {
-                    throw new ArgumentException(
-                        $"Invalid default property value. Null is not a valid value for {typeof(TValue)}.");
-                }
-            }
-
-            return metadata;
+            return (o, v) => validate((THost)o, v);
         }
     }
 }

+ 29 - 13
src/Perspex.Base/StyledPropertyMetadata.cs → src/Perspex.Base/StyledPropertyMetadata`1.cs

@@ -2,28 +2,27 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 using System;
+using System.Diagnostics;
 using Perspex.Data;
 
 namespace Perspex
 {
     /// <summary>
-    /// Styled perspex property metadata.
+    /// Metadata for styled perspex properties.
     /// </summary>
-    public class StyledPropertyMetadata : PropertyMetadata
+    public class StyledPropertyMetadata<TValue> : PropertyMetadata, IStyledPropertyMetadata
     {
         /// <summary>
-        /// Initializes a new instance of the <see cref="StyledPropertyMetadata"/> class.
+        /// Initializes a new instance of the <see cref="StyledPropertyMetadata{TValue}"/> class.
         /// </summary>
         /// <param name="defaultValue">The default value of the property.</param>
         /// <param name="validate">A validation function.</param>
         /// <param name="defaultBindingMode">The default binding mode.</param>
-        /// <param name="notifyingCallback">The property notifying callback.</param>
         public StyledPropertyMetadata(
-            object defaultValue,
-            Func<IPerspexObject, object, object> validate = null,
-            BindingMode defaultBindingMode = BindingMode.Default,
-            Action<IPerspexObject, bool> notifyingCallback = null)
-                : base(defaultBindingMode, notifyingCallback)
+            TValue defaultValue = default(TValue),
+            Func<IPerspexObject, TValue, TValue> validate = null,
+            BindingMode defaultBindingMode = BindingMode.Default)
+                : base(defaultBindingMode)
         {
             DefaultValue = defaultValue;
             Validate = validate;
@@ -32,19 +31,23 @@ namespace Perspex
         /// <summary>
         /// Gets the default value for the property.
         /// </summary>
-        public object DefaultValue { get; private set; }
+        public TValue DefaultValue { get; private set; }
 
         /// <summary>
         /// Gets the validation callback.
         /// </summary>
-        public Func<IPerspexObject, object, object> Validate { get; private set; }
+        public Func<IPerspexObject, TValue, TValue> Validate { get; private set; }
+
+        object IStyledPropertyMetadata.DefaultValue => DefaultValue;
+
+        Func<IPerspexObject, object, object> IStyledPropertyMetadata.Validate => Cast(Validate);
 
         /// <inheritdoc/>
         public override void Merge(PropertyMetadata baseMetadata, PerspexProperty property)
         {
             base.Merge(baseMetadata, property);
 
-            var src = baseMetadata as StyledPropertyMetadata;
+            var src = baseMetadata as StyledPropertyMetadata<TValue>;
 
             if (src != null)
             {
@@ -53,11 +56,24 @@ namespace Perspex
                     DefaultValue = src.DefaultValue;
                 }
 
-                if (Validate != null)
+                if (Validate == null)
                 {
                     Validate = src.Validate;
                 }
             }
         }
+
+        [DebuggerHidden]
+        private static Func<IPerspexObject, object, object> Cast(Func<IPerspexObject, TValue, TValue> f)
+        {
+            if (f == null)
+            {
+                return null;
+            }
+            else
+            {
+                return (o, v) => f(o, (TValue)v);
+            }
+        }
     }
 }

+ 6 - 1
src/Perspex.Controls/Presenters/TextPresenter.cs

@@ -12,7 +12,7 @@ namespace Perspex.Controls.Presenters
 {
     public class TextPresenter : TextBlock
     {
-        public static readonly PerspexProperty<int> CaretIndexProperty =
+        public static readonly StyledProperty<int> CaretIndexProperty =
             TextBox.CaretIndexProperty.AddOwner<TextPresenter>();
 
         public static readonly PerspexProperty<int> SelectionStartProperty =
@@ -27,6 +27,11 @@ namespace Perspex.Controls.Presenters
 
         private IObservable<bool> _canScrollHorizontally;
 
+        static TextPresenter()
+        {
+            CaretIndexProperty.OverrideValidation<TextPresenter>((o, v) => v);
+        }
+
         public TextPresenter()
         {
             _caretTimer = new DispatcherTimer();

+ 1 - 2
tests/Perspex.Base.UnitTests/AttachedPropertyTests.cs

@@ -13,8 +13,7 @@ namespace Perspex.Base.UnitTests
             var property = new AttachedProperty<string>(
                 "Foo",
                 typeof(Class1),
-                false,
-                new StyledPropertyMetadata(null));
+                new StyledPropertyMetadata<string>());
 
             Assert.True(property.IsAttached);
         }

+ 4 - 4
tests/Perspex.Base.UnitTests/PerspexPropertyRegistryTests.cs

@@ -91,7 +91,7 @@ namespace Perspex.Base.UnitTests
         {
             var result = PerspexPropertyRegistry.Instance.FindRegistered(typeof(Class3), "Attached");
 
-            Assert.Equal(AttachedOwner.AttachedProperty, result);
+            Assert.True(AttachedOwner.AttachedProperty == result);
         }
 
         [Fact]
@@ -99,7 +99,7 @@ namespace Perspex.Base.UnitTests
         {
             var result = PerspexPropertyRegistry.Instance.FindRegistered(typeof(Class3), "Class3.Attached");
 
-            Assert.Equal(AttachedOwner.AttachedProperty, result);
+            Assert.True(AttachedOwner.AttachedProperty == result);
         }
 
         [Fact]
@@ -107,7 +107,7 @@ namespace Perspex.Base.UnitTests
         {
             var result = PerspexPropertyRegistry.Instance.FindRegistered(typeof(Class3), "AttachedOwner.Attached");
 
-            Assert.Equal(AttachedOwner.AttachedProperty, result);
+            Assert.True(AttachedOwner.AttachedProperty == result);
         }
 
         [Fact]
@@ -115,7 +115,7 @@ namespace Perspex.Base.UnitTests
         {
             var result = PerspexPropertyRegistry.Instance.FindRegistered(typeof(Class3), "Class1.Attached");
 
-            Assert.Equal(AttachedOwner.AttachedProperty, result);
+            Assert.True(AttachedOwner.AttachedProperty == result);
         }
 
         [Fact]

+ 1 - 2
tests/Perspex.Base.UnitTests/PerspexPropertyTests.cs

@@ -69,14 +69,13 @@ namespace Perspex.Base.UnitTests
         {
             var metadata = new PropertyMetadata(BindingMode.TwoWay);
             var notify = (Action<IPerspexObject, bool>)((a, b) => { });
-            var overridden = new PropertyMetadata(notifyingCallback: notify);
+            var overridden = new PropertyMetadata();
             var target = new TestProperty<string>("test", typeof(Class1), metadata);
 
             target.OverrideMetadata<Class2>(overridden);
 
             var result = target.GetMetadata<Class2>();
             Assert.Equal(BindingMode.TwoWay, result.DefaultBindingMode);
-            Assert.Equal(notify, result.NotifyingCallback);
         }
 
         [Fact]

+ 2 - 4
tests/Perspex.Base.UnitTests/StyledPropertyTests.cs

@@ -13,8 +13,7 @@ namespace Perspex.Base.UnitTests
             var p1 = new StyledProperty<string>(
                 "p1", 
                 typeof(Class1), 
-                false,
-                new StyledPropertyMetadata(null));
+                new StyledPropertyMetadata<string>());
             var p2 = p1.AddOwner<Class2>();
 
             Assert.Equal(p1, p2);
@@ -28,8 +27,7 @@ namespace Perspex.Base.UnitTests
             var p1 = new StyledProperty<string>(
                 "p1",
                 typeof(Class1),
-                false,
-                new StyledPropertyMetadata(null));
+                new StyledPropertyMetadata<string>());
             var p2 = p1.AddOwner<Class2>();
 
             Assert.Same(p1, p2);