Browse Source

Supply UnsetValue for DirectProperty.

When a direct property is set to UnsetValue, previously it used
default(TValue). Allow that value to be overridden and make it be -1 for
SelectingItemsControl.SelectedIndex.
pull/467/head
Steven Kirk 10 years ago
parent
commit
21ae855a06
  1. 52
      src/Perspex.Base/DirectPropertyMetadata`1.cs
  2. 16
      src/Perspex.Base/IDirectPropertyMetadata.cs
  3. 2
      src/Perspex.Base/Perspex.Base.csproj
  4. 37
      src/Perspex.Base/PerspexObject.cs
  5. 9
      src/Perspex.Base/PerspexProperty.cs
  6. 3
      src/Perspex.Controls/Primitives/SelectingItemsControl.cs
  7. 3
      src/Perspex.Controls/Primitives/ToggleButton.cs
  8. 29
      tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs

52
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
{
/// <summary>
/// Metadata for direct perspex properties.
/// </summary>
public class DirectPropertyMetadata<TValue> : PropertyMetadata, IDirectPropertyMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="StyledPropertyMetadata{TValue}"/> class.
/// </summary>
/// <param name="unsetValue">
/// The value to use when the property is set to <see cref="PerspexProperty.UnsetValue"/>
/// </param>
/// <param name="defaultBindingMode">The default binding mode.</param>
public DirectPropertyMetadata(
TValue unsetValue = default(TValue),
BindingMode defaultBindingMode = BindingMode.Default)
: base(defaultBindingMode)
{
UnsetValue = unsetValue;
}
/// <summary>
/// Gets the to use when the property is set to <see cref="PerspexProperty.UnsetValue"/>.
/// </summary>
public TValue UnsetValue { get; private set; }
/// <inheritdoc/>
object IDirectPropertyMetadata.UnsetValue => UnsetValue;
/// <inheritdoc/>
public override void Merge(PropertyMetadata baseMetadata, PerspexProperty property)
{
base.Merge(baseMetadata, property);
var src = baseMetadata as DirectPropertyMetadata<TValue>;
if (src != null)
{
if (UnsetValue == null)
{
UnsetValue = src.UnsetValue;
}
}
}
}
}

16
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
{
/// <summary>
/// Untyped interface to <see cref="DirectPropertyMetadata{TValue}"/>
/// </summary>
public interface IDirectPropertyMetadata
{
/// <summary>
/// Gets the to use when the property is set to <see cref="PerspexProperty.UnsetValue"/>.
/// </summary>
object UnsetValue { get; }
}
}

2
src/Perspex.Base/Perspex.Base.csproj

@ -56,6 +56,7 @@
<Compile Include="IDirectPropertyAccessor.cs" />
<Compile Include="DirectProperty.cs" />
<Compile Include="IPerspexObject.cs" />
<Compile Include="IDirectPropertyMetadata.cs" />
<Compile Include="IStyledPropertyMetadata.cs" />
<Compile Include="ISupportInitialize.cs" />
<Compile Include="Metadata\DependsOnAttribute.cs" />
@ -92,6 +93,7 @@
<Compile Include="Reactive\AnonymousSubject`1.cs" />
<Compile Include="Reactive\AnonymousSubject`2.cs" />
<Compile Include="Reactive\PerspexObservable.cs" />
<Compile Include="DirectPropertyMetadata`1.cs" />
<Compile Include="StyledPropertyMetadata`1.cs" />
<Compile Include="Threading\Dispatcher.cs" />
<Compile Include="Threading\DispatcherPriority.cs" />

37
src/Perspex.Base/PerspexObject.cs

@ -268,14 +268,7 @@ namespace Perspex
{
Contract.Requires<ArgumentNullException>(property != null);
if (property.IsDirect)
{
return (T)((IDirectPropertyAccessor)GetRegistered(property)).GetValue(this);
}
else
{
return (T)GetValue((PerspexProperty)property);
}
return (T)GetValue((PerspexProperty)property);
}
/// <summary>
@ -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
}
}
/// <summary>
/// Converts an unset value to the default value for a property type.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
private static object UnsetToDefault(object value, PerspexProperty property)
{
return value == PerspexProperty.UnsetValue ?
TypeUtilities.Default(property.PropertyType) :
value;
}
/// <summary>
/// Creates a <see cref="PriorityValue"/> for a <see cref="PerspexProperty"/>.
/// </summary>
@ -626,6 +606,19 @@ namespace Perspex
return result;
}
/// <summary>
/// Converts an unset value to the default value for a direct property.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
private object DirectUnsetToDefault(object value, PerspexProperty property)
{
return value == PerspexProperty.UnsetValue ?
((IDirectPropertyMetadata)property.GetMetadata(GetType())).UnsetValue :
value;
}
/// <summary>
/// Gets the default value for a property.
/// </summary>

9
src/Perspex.Base/PerspexProperty.cs

@ -342,18 +342,25 @@ namespace Perspex
/// <param name="name">The name of the property.</param>
/// <param name="getter">Gets the current value of the property.</param>
/// <param name="setter">Sets the value of the property.</param>
/// <param name="unsetValue">
/// The value to use when the property is set to <see cref="PerspexProperty.UnsetValue"/>
/// </param>
/// <param name="defaultBindingMode">The default binding mode for the property.</param>
/// <returns>A <see cref="PerspexProperty{TValue}"/></returns>
public static DirectProperty<TOwner, TValue> RegisterDirect<TOwner, TValue>(
string name,
Func<TOwner, TValue> getter,
Action<TOwner, TValue> setter = null,
TValue unsetValue = default(TValue),
BindingMode defaultBindingMode = BindingMode.OneWay)
where TOwner : IPerspexObject
{
Contract.Requires<ArgumentNullException>(name != null);
var metadata = new PropertyMetadata(defaultBindingMode);
var metadata = new DirectPropertyMetadata<TValue>(
unsetValue: unsetValue,
defaultBindingMode: defaultBindingMode);
var result = new DirectProperty<TOwner, TValue>(name, getter, setter, metadata);
PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result);
return result;

3
src/Perspex.Controls/Primitives/SelectingItemsControl.cs

@ -53,7 +53,8 @@ namespace Perspex.Controls.Primitives
PerspexProperty.RegisterDirect<SelectingItemsControl, int>(
nameof(SelectedIndex),
o => o.SelectedIndex,
(o, v) => o.SelectedIndex = v);
(o, v) => o.SelectedIndex = v,
unsetValue: -1);
/// <summary>
/// Defines the <see cref="SelectedItem"/> property.

3
src/Perspex.Controls/Primitives/ToggleButton.cs

@ -13,7 +13,8 @@ namespace Perspex.Controls.Primitives
PerspexProperty.RegisterDirect<ToggleButton, bool>(
"IsChecked",
o => o.IsChecked,
(o,v) => o.IsChecked = v, BindingMode.TwoWay);
(o,v) => o.IsChecked = v,
defaultBindingMode: BindingMode.TwoWay);
private bool _isChecked;

29
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<object>();
@ -171,7 +171,7 @@ namespace Perspex.Base.UnitTests
source.OnNext(6);
Assert.Equal(6, target.Baz);
source.OnNext(PerspexProperty.UnsetValue);
Assert.Equal(0, target.Baz);
Assert.Equal(-1, target.Baz);
}
[Fact]
@ -282,6 +282,17 @@ namespace Perspex.Base.UnitTests
Assert.Equal("newvalue", target.Foo);
}
[Fact]
public void UnsetValue_Is_Used_On_AddOwnered_Property()
{
var target = new Class2();
target.SetValue((PerspexProperty)Class1.FooProperty, PerspexProperty.UnsetValue);
Assert.Equal("unset", target.Foo);
}
[Fact]
public void Bind_Binds_AddOwnered_Property_Value()
{
@ -342,13 +353,21 @@ namespace Perspex.Base.UnitTests
private class Class1 : PerspexObject
{
public static readonly DirectProperty<Class1, string> FooProperty =
PerspexProperty.RegisterDirect<Class1, string>("Foo", o => o.Foo, (o, v) => o.Foo = v);
PerspexProperty.RegisterDirect<Class1, string>(
"Foo",
o => o.Foo,
(o, v) => o.Foo = v,
unsetValue: "unset");
public static readonly DirectProperty<Class1, string> BarProperty =
PerspexProperty.RegisterDirect<Class1, string>("Bar", o => o.Bar);
public static readonly DirectProperty<Class1, int> BazProperty =
PerspexProperty.RegisterDirect<Class1, int>("Bar", o => o.Baz, (o,v) => o.Baz = v);
PerspexProperty.RegisterDirect<Class1, int>(
"Bar",
o => o.Baz,
(o,v) => o.Baz = v,
unsetValue: -1);
private string _foo = "initial";
private readonly string _bar = "bar";

Loading…
Cancel
Save