【问题标题】:DependencyProperty CoerceValueCallback with genericDependencyProperty CoerceValueCallback 与泛型
【发布时间】:2016-11-22 07:20:04
【问题描述】:

我正在构建一个使用 DependencyProperty 和泛型的 wpf 控件,为此我需要(至少我认为)一个 CoerceValueCallback 来检查值是否正确。 这个想法是构建一个基类,我将从中派生出数字类型。

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 正在返回一个对象,而我找不到如何返回泛型。

有什么想法吗?

编辑:感谢以下答案,这是我所做的

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;
    }
}

这样,我可以将 Value 限制在 MinValue 和 MaxValue 之内,并使所有内容都保持泛型,从而避免在每个派生类中重写抽象方法。

【问题讨论】:

  • 将返回值更改为T时发生了什么?
  • 在什么意义上“返回泛型”?
  • "private static T CoerceValue(DependencyObject d, object baseValue) { // 检查值是否有效 return verifyValue; }" 这样,Visual Studio 告诉我该方法的返回类型错误跨度>
  • 这里的值怎么会无效?您不需要 CoerceValueCallback。
  • 该值必须保持在给定范围内。 Corcevalue 应该检查

标签: c# wpf generics dependency-properties


【解决方案1】:

像这样添加一个抽象的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));
    }
}

【讨论】:

  • 您不能将“null”作为默认值传递给 PropertyMetadata,因为 T 是结构体。
  • 效果也很好,但有点麻烦,因为我必须为每个派生类重写抽象方法。还是谢谢
  • 我仍然很好奇如果没有这种抽象方法,范围检查将如何工作。
【解决方案2】:

虽然您的控件可以使用泛型,但在使用CoerceValueCallback 时,您必须维护委托回调。 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。

【讨论】:

  • 你注意到where T : struct了吗?检查null 毫无意义。
  • baseValue as T 不会编译。
  • 演员阵容确实有效@ClémentPlantec。我注意到我在回答中解决了您的代码的另一个问题。
  • @techvice 确实,您的解决方案非常有效,谢谢!
  • @ClémentPlantec 现在实际范围检查是如何工作的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-12
  • 2021-02-21
  • 2012-06-28
相关资源
最近更新 更多