具有泛型的 DependencyProperty CoerceValueCallback
DependencyProperty CoerceValueCallback with generic
我正在构建一个使用 DependencyProperty 和泛型的 wpf 控件,为此我需要(至少我认为)一个 CoerceValueCallback 来检查值是否正确。
我的想法是建立一个基础class,我将从中派生出数字类型。
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>
{
}
问题是 CoerceValue 是 return 一个对象,我找不到如何 return 一个泛型。
有什么想法吗?
编辑:感谢下面的答案,这是我所做的
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;
}
}
这样,我可以将值限制在 MinValue 和 MaxValue 之内,并使所有内容保持通用,从而避免在每个派生 class 中重写抽象方法。
虽然您的控件可以使用泛型,但在使用 CoerceValueCallback, you will have to maintain the delegate callback. The C# documentation 时指定委托是密封的。
我还注意到您的 PropertyMetadata
有问题。您将 null 作为默认值传递。当我之前检查 null 时,这让我措手不及。这是我测试时对我有用的代码:
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;
}
}
获得从 CoerceValue 方法返回的值后,您必须将其转换为 T。
像这样添加抽象 CoerceValue
方法:
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));
}
}
我正在构建一个使用 DependencyProperty 和泛型的 wpf 控件,为此我需要(至少我认为)一个 CoerceValueCallback 来检查值是否正确。 我的想法是建立一个基础class,我将从中派生出数字类型。
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>
{
}
问题是 CoerceValue 是 return 一个对象,我找不到如何 return 一个泛型。
有什么想法吗?
编辑:感谢下面的答案,这是我所做的
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;
}
}
这样,我可以将值限制在 MinValue 和 MaxValue 之内,并使所有内容保持通用,从而避免在每个派生 class 中重写抽象方法。
虽然您的控件可以使用泛型,但在使用 CoerceValueCallback, you will have to maintain the delegate callback. The C# documentation 时指定委托是密封的。
我还注意到您的 PropertyMetadata
有问题。您将 null 作为默认值传递。当我之前检查 null 时,这让我措手不及。这是我测试时对我有用的代码:
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;
}
}
获得从 CoerceValue 方法返回的值后,您必须将其转换为 T。
像这样添加抽象 CoerceValue
方法:
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));
}
}