Reputation: 107
I'm building a wpf control that use DependencyProperty with generic, for which I need (at least I think) a CoerceValueCallback to check if the value is correct. The idea is to build a base class from which I'll derive with number type.
public class MyClass<T> : Control where T : struct
{
public T Value
{
get { return (T)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// DependencyProperty as the backing store for Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value",
typeof(T),
typeof(MyClass<T>),
new PropertyMetadata(null, null, CoerceValue)
);
private static object CoerceValue(DependencyObject d, object baseValue)
{
// Check if value is valid
return verifiedValue;
}
}
public class MyDerivedClass : MyClass<int>
{
}
Problem is that the CoerceValue is returning an object and I can't find how to return a generic instead.
Any idea ?
EDIT: Here is what I did thanks to the answers below
public abstract class MyClass<T> : Control where T : struct, IComparable
{
public T MinValue { get; set; }
public T MaxValue { get; set; }
public T Value
{
get { return (T)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// DependencyProperty as the backing store for Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value",
typeof(T),
typeof(MyClass<T>),
new PropertyMetadata(default(T), null, CoerceValue)
);
private static object CoerceValue(DependencyObject d, object baseValue)
{
T value = (T)baseValue;
((MyClass<T>)d).CoerceValueToBounds(ref value);
return value;
}
private void CoerceValueToBounds(ref T value)
{
if (value.CompareTo(MinValue) < 0)
value = MinValue;
else if (value.CompareTo(MaxValue) > 0)
value = MaxValue;
}
}
This way, I can limit the Value within MinValue and MaxValue and keeping everything with generic, thus avoiding overriding an abstract method in every derived class.
Upvotes: 0
Views: 687
Reputation: 128097
Add an abstract CoerceValue
method like this:
public abstract class MyClass<T> : Control where T : struct
{
...
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(T), typeof(MyClass<T>),
new PropertyMetadata(default(T), null, CoerceValue));
protected abstract T CoerceValue(T value);
private static object CoerceValue(DependencyObject d, object value)
{
return ((MyClass<T>)d).CoerceValue((T)value);
}
}
public class MyDerivedClass : MyClass<int>
{
protected override int CoerceValue(int value)
{
return Math.Max(100, Math.Min(200, value));
}
}
Upvotes: 1
Reputation: 1301
While your control can utilize the generic, when using the CoerceValueCallback, you will have to maintain the delegate callback. The C# documentation specifies that delegates are sealed.
I also noticed you have an issue with your PropertyMetadata
. You are passing null as the default value. Which is what caught me off guard when I previously checked for null. Here is the code that worked for me when I tested it:
public class MyClass<T> : Control where T : struct
{
public T Value
{
get { return (T)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// DependencyProperty as the backing store for Value
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value",
typeof(T),
typeof(MyClass<T>),
new PropertyMetadata(default(T), null, CoerceValue) //Must pass default(T) otherwise an exception will occur.
);
private static object CoerceValue(DependencyObject d, object baseValue)
{
var tValue = (T)baseValue;
// Check if tValue is valid
return tValue;
}
}
Once you have the value returned from the CoerceValue method, you will have to cast it to T.
Upvotes: 0