Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class PropertyMetadataBuilder<T, TValue> where T : DependencyObject
- {
- private readonly PropertyMetadata _propertyMetadata;
- internal PropertyMetadataBuilder()
- {
- _propertyMetadata = new PropertyMetadata();
- }
- public PropertyMetadataBuilder<T, TValue> DefaultValue(
- TValue defaultValue
- )
- {
- _propertyMetadata.DefaultValue = defaultValue;
- return this;
- }
- public PropertyMetadataBuilder<T, TValue> PropertyChanged(
- Action<T, DependencyPropertyChangedEventArgs<TValue>> propertyChangedCallback
- )
- {
- _propertyMetadata.PropertyChangedCallback = new PropertyChangedCallback(
- (sender, e) =>
- propertyChangedCallback((T)sender,
- new DependencyPropertyChangedEventArgs<TValue>(e)
- )
- );
- return this;
- }
- public PropertyMetadataBuilder<T, TValue> PropertyChanging(
- Action<T, PropertyChangingEventArgs<TValue>> coerceValueCallback
- )
- {
- _propertyMetadata.CoerceValueCallback = new CoerceValueCallback(
- (d, baseValue) =>
- {
- var e = new PropertyChangingEventArgs<TValue>((TValue)baseValue);
- coerceValueCallback((T)d, e);
- return
- e.Canceled
- ? DependencyProperty.UnsetValue
- : e.CoercedValue;
- }
- );
- return this;
- }
- public static implicit operator PropertyMetadata(
- PropertyMetadataBuilder<T, TValue> builder
- )
- {
- return builder._propertyMetadata;
- }
- }
- static class DependencyPropertyBuilderExtensions
- {
- public static DependencyPropertyBuilder<T, TValue> PropertyMetadata<T, TValue>(
- this DependencyPropertyBuilder<T, TValue> builder,
- Action<PropertyMetadataBuilder<T, TValue>> build
- ) where T : DependencyObject
- {
- var metadataBuilder = new PropertyMetadataBuilder<T, TValue>();
- build(metadataBuilder);
- return builder.Metadata(metadataBuilder);
- }
- }
- public DependencyPropertyBuilder<T, TValue> Metadata(
- PropertyMetadata propertyMetadata
- )
- {
- _propertyMetadata = propertyMetadata;
- return this;
- }
- class PropertyChangingEventArgs<TValue> : EventArgs
- {
- internal PropertyChangingEventArgs(TValue baseValue)
- {
- NewValue = baseValue;
- CoercedValue = baseValue;
- }
- public TValue NewValue { get; }
- public TValue CoercedValue { get; set; }
- public bool Canceled { get; set; }
- }
- public PropertyMetadataBuilder<T, TValue> PropertyChanging(
- Action<T, PropertyChangingEventArgs<TValue>> coerceValueCallback
- )
- {
- _propertyMetadata.CoerceValueCallback = new CoerceValueCallback(
- (d, baseValue) =>
- {
- var e = new PropertyChangingEventArgs<TValue>((TValue)baseValue);
- coerceValueCallback((T)d, e);
- return
- e.Canceled
- ? DependencyProperty.UnsetValue
- : e.CoercedValue;
- }
- );
- return this;
- }
- class TestObject : DependencyObject
- {
- public static readonly DependencyProperty CountProperty =
- DependencyPropertyBuilder
- .Register<TestObject, int>(nameof(TestObject.Count))
- .PropertyMetadata(b => b
- .DefaultValue(5)
- .PropertyChanged((testObject, e) =>
- {
- Console.WriteLine($"{e.Property.Name} = {e.OldValue} --> {e.NewValue}");
- })
- .PropertyChanging((testObject, e) =>
- {
- if (e.NewValue > 20)
- {
- e.CoercedValue = 15;
- }
- if (e.NewValue < 1)
- {
- e.Canceled = true;
- }
- })
- ).ValidateValue(value => value >= 0);
- public int Count
- {
- get { return CountProperty.GetValue<int>(this); }
- set { CountProperty.SetValue(this, value); }
- }
- }
- var testObject = new TestObject();
- testObject.Count.Dump("Default");
- testObject.Count2 = 8;
- testObject.Count2.Dump("Changed");
- testObject.Count = 22;
- testObject.Count.Dump("Coerced to max");
- testObject.Count = 0;
- testObject.Count.Dump("Property change canceled");
- testObject.Count = -2; // bam!
- public DependencyProperty Build()
- {
- BuildDefaultValue();
- BuildValidateValueCallback();
- return DependencyProperty.Register(
- _name,
- _propertyType,
- _ownerType,
- _propertyMetadata,
- _validateValueCallback
- );
- }
- private void BuildDefaultValue()
- {
- var property = _ownerType.GetProperty(_name);
- // Use the default value specified by the user or try to use the attribute.
- _propertyMetadata.DefaultValue =
- _propertyMetadata.DefaultValue ??
- new Func<object>(() =>
- // Get the defualt value from the attribute...
- property.GetCustomAttribute<DefaultValueAttribute>()?.Value ??
- // or use the default value for the type.
- (property.PropertyType.IsValueType
- ? Activator.CreateInstance(property.PropertyType)
- : null
- )
- )();
- }
- private void BuildValidateValueCallback()
- {
- var property = _ownerType.GetProperty(_name);
- // Use the callback specified by the user or try to use the attributes.
- _validateValueCallback =
- _validateValueCallback ??
- (value =>
- new Func<bool>(() => (
- property.GetCustomAttributes<ValidationAttribute>() ??
- Enumerable.Empty<ValidationAttribute>()
- ).All(x => x.IsValid(value)))()
- );
- }
- public PropertyMetadataBuilder<T, TValue> CoerceValue(
- Func<T, TValue, object> coerceValueCallback
- )
- {
- _propertyMetadata.CoerceValueCallback = (d, baseValue) =>
- coerceValueCallback((T) d, (TValue)baseValue);
- return this;
- }
- public static PropertyMetadataBuilder<T, TValue> CoerceValue<T, TValue>(
- this PropertyMetadataBuilder<T, TValue> builder,
- Action<T, CoerceValueEventArgs<TValue>> coerceValueCallback
- ) where T : DependencyObject
- {
- builder.CoerceValue((d, baseValue) =>
- {
- var e = new CoerceValueEventArgs<TValue>(baseValue);
- coerceValueCallback(d, e);
- return
- e.Canceled
- ? DependencyProperty.UnsetValue
- : e.CoercedValue;
- });
- return builder;
- }
- public class CoerceValueEventArgs<TValue> : EventArgs
- {
- internal CoerceValueEventArgs(TValue baseValue)
- {
- NewValue = baseValue;
- CoercedValue = baseValue;
- }
- public TValue NewValue { get; }
- public TValue CoercedValue { get; set; }
- public bool Canceled { get; set; }
- }
- internal class TestObject : DependencyObject
- {
- public static readonly DependencyProperty CountProperty =
- DependencyPropertyBuilder
- .Register<TestObject, int>(nameof(Count))
- .PropertyMetadata(b => b
- .PropertyChanged((testObject, e) =>
- {
- Console.WriteLine($"{e.Property.Name} = {e.OldValue} --> {e.NewValue}");
- })
- .CoerceValue((testObject, e) =>
- {
- if (e.NewValue > 20)
- {
- e.CoercedValue = 15;
- }
- if (e.NewValue < 1)
- {
- e.Canceled = true;
- }
- })
- );
- [DefaultValue(5)]
- [Range(0, 15)]
- public int Count
- {
- get { return CountProperty.GetValue<int>(this); }
- set { CountProperty.SetValue(this, value); }
- }
- }
- [TestMethod]
- public void Count_DefaultValue()
- {
- var testObject = new TestObject();
- Assert.AreEqual(5, testObject.Count, "Default value.");
- }
- [TestMethod]
- public void Count_ChangeValue()
- {
- var testObject = new TestObject
- {
- Count = 8
- };
- Assert.AreEqual(8, testObject.Count, "Changed value");
- }
- [TestMethod]
- [ExpectedException(typeof(ArgumentException))]
- public void Count_ValueOutOfRange()
- {
- new TestObject
- {
- Count = 22
- };
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement