diff --git a/src/Perspex.Base/DirectPropertyMetadata`1.cs b/src/Perspex.Base/DirectPropertyMetadata`1.cs
new file mode 100644
index 0000000000..162fc788fc
--- /dev/null
+++ b/src/Perspex.Base/DirectPropertyMetadata`1.cs
@@ -0,0 +1,52 @@
+// 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 Perspex.Data;
+
+namespace Perspex
+{
+ ///
+ /// Metadata for direct perspex properties.
+ ///
+ public class DirectPropertyMetadata : PropertyMetadata, IDirectPropertyMetadata
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The value to use when the property is set to
+ ///
+ /// The default binding mode.
+ public DirectPropertyMetadata(
+ TValue unsetValue = default(TValue),
+ BindingMode defaultBindingMode = BindingMode.Default)
+ : base(defaultBindingMode)
+ {
+ UnsetValue = unsetValue;
+ }
+
+ ///
+ /// Gets the to use when the property is set to .
+ ///
+ public TValue UnsetValue { get; private set; }
+
+ ///
+ object IDirectPropertyMetadata.UnsetValue => UnsetValue;
+
+ ///
+ public override void Merge(PropertyMetadata baseMetadata, PerspexProperty property)
+ {
+ base.Merge(baseMetadata, property);
+
+ var src = baseMetadata as DirectPropertyMetadata;
+
+ if (src != null)
+ {
+ if (UnsetValue == null)
+ {
+ UnsetValue = src.UnsetValue;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Perspex.Base/IDirectPropertyMetadata.cs b/src/Perspex.Base/IDirectPropertyMetadata.cs
new file mode 100644
index 0000000000..72c55300ed
--- /dev/null
+++ b/src/Perspex.Base/IDirectPropertyMetadata.cs
@@ -0,0 +1,16 @@
+// 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.
+
+namespace Perspex
+{
+ ///
+ /// Untyped interface to
+ ///
+ public interface IDirectPropertyMetadata
+ {
+ ///
+ /// Gets the to use when the property is set to .
+ ///
+ object UnsetValue { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Perspex.Base/Perspex.Base.csproj b/src/Perspex.Base/Perspex.Base.csproj
index b886e9b08b..c06cdbe16b 100644
--- a/src/Perspex.Base/Perspex.Base.csproj
+++ b/src/Perspex.Base/Perspex.Base.csproj
@@ -56,6 +56,7 @@
+
@@ -92,6 +93,7 @@
+
diff --git a/src/Perspex.Base/PerspexObject.cs b/src/Perspex.Base/PerspexObject.cs
index c3b6f321f0..16819428ca 100644
--- a/src/Perspex.Base/PerspexObject.cs
+++ b/src/Perspex.Base/PerspexObject.cs
@@ -268,14 +268,7 @@ namespace Perspex
{
Contract.Requires(property != null);
- if (property.IsDirect)
- {
- return (T)((IDirectPropertyAccessor)GetRegistered(property)).GetValue(this);
- }
- else
- {
- return (T)GetValue((PerspexProperty)property);
- }
+ return (T)GetValue((PerspexProperty)property);
}
///
@@ -315,7 +308,7 @@ namespace Perspex
{
var accessor = (IDirectPropertyAccessor)GetRegistered(property);
LogPropertySet(property, value, priority);
- accessor.SetValue(this, UnsetToDefault(value, property));
+ accessor.SetValue(this, DirectUnsetToDefault(value, property));
}
else
{
@@ -567,19 +560,6 @@ namespace Perspex
}
}
- ///
- /// Converts an unset value to the default value for a property type.
- ///
- /// The value.
- /// The property.
- /// The value.
- private static object UnsetToDefault(object value, PerspexProperty property)
- {
- return value == PerspexProperty.UnsetValue ?
- TypeUtilities.Default(property.PropertyType) :
- value;
- }
-
///
/// Creates a for a .
///
@@ -626,6 +606,19 @@ namespace Perspex
return result;
}
+ ///
+ /// Converts an unset value to the default value for a direct property.
+ ///
+ /// The value.
+ /// The property.
+ /// The value.
+ private object DirectUnsetToDefault(object value, PerspexProperty property)
+ {
+ return value == PerspexProperty.UnsetValue ?
+ ((IDirectPropertyMetadata)property.GetMetadata(GetType())).UnsetValue :
+ value;
+ }
+
///
/// Gets the default value for a property.
///
diff --git a/src/Perspex.Base/PerspexProperty.cs b/src/Perspex.Base/PerspexProperty.cs
index 8998627849..71dd7bb0fb 100644
--- a/src/Perspex.Base/PerspexProperty.cs
+++ b/src/Perspex.Base/PerspexProperty.cs
@@ -342,18 +342,25 @@ namespace Perspex
/// The name of the property.
/// Gets the current value of the property.
/// Sets the value of the property.
+ ///
+ /// The value to use when the property is set to
+ ///
/// The default binding mode for the property.
/// A
public static DirectProperty RegisterDirect(
string name,
Func getter,
Action setter = null,
+ TValue unsetValue = default(TValue),
BindingMode defaultBindingMode = BindingMode.OneWay)
where TOwner : IPerspexObject
{
Contract.Requires(name != null);
- var metadata = new PropertyMetadata(defaultBindingMode);
+ var metadata = new DirectPropertyMetadata(
+ unsetValue: unsetValue,
+ defaultBindingMode: defaultBindingMode);
+
var result = new DirectProperty(name, getter, setter, metadata);
PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result);
return result;
diff --git a/src/Perspex.Controls/Primitives/SelectingItemsControl.cs b/src/Perspex.Controls/Primitives/SelectingItemsControl.cs
index f6e405a24a..4d9482e7de 100644
--- a/src/Perspex.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Perspex.Controls/Primitives/SelectingItemsControl.cs
@@ -53,7 +53,8 @@ namespace Perspex.Controls.Primitives
PerspexProperty.RegisterDirect(
nameof(SelectedIndex),
o => o.SelectedIndex,
- (o, v) => o.SelectedIndex = v);
+ (o, v) => o.SelectedIndex = v,
+ unsetValue: -1);
///
/// Defines the property.
@@ -62,7 +63,8 @@ namespace Perspex.Controls.Primitives
PerspexProperty.RegisterDirect(
nameof(SelectedItem),
o => o.SelectedItem,
- (o, v) => o.SelectedItem = v, BindingMode.TwoWay);
+ (o, v) => o.SelectedItem = v,
+ defaultBindingMode: BindingMode.TwoWay);
///
/// Defines the property.
diff --git a/src/Perspex.Controls/Primitives/ToggleButton.cs b/src/Perspex.Controls/Primitives/ToggleButton.cs
index c0aedf00ba..30b76aea1c 100644
--- a/src/Perspex.Controls/Primitives/ToggleButton.cs
+++ b/src/Perspex.Controls/Primitives/ToggleButton.cs
@@ -13,7 +13,8 @@ namespace Perspex.Controls.Primitives
PerspexProperty.RegisterDirect(
"IsChecked",
o => o.IsChecked,
- (o,v) => o.IsChecked = v, BindingMode.TwoWay);
+ (o,v) => o.IsChecked = v,
+ defaultBindingMode: BindingMode.TwoWay);
private bool _isChecked;
diff --git a/tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs b/tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs
index 93261fa01a..6c5b43888f 100644
--- a/tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs
+++ b/tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs
@@ -62,7 +62,7 @@ namespace Perspex.Base.UnitTests
target.SetValue((PerspexProperty)Class1.BazProperty, PerspexProperty.UnsetValue);
- Assert.Equal(0, target.Baz);
+ Assert.Equal(-1, target.Baz);
}
[Fact]
@@ -160,7 +160,7 @@ namespace Perspex.Base.UnitTests
}
[Fact]
- public void Bind_NonGeneric_Coerces_UnsetValue()
+ public void Bind_NonGeneric_Uses_UnsetValue()
{
var target = new Class1();
var source = new Subject