Pregunta

Tengo un control con un DependencyProperty con un CoerceValueCallback. Esta propiedad está ligado a una propiedad de un objeto modelo.

Al establecer la propiedad de control a un valor que hace que la coacción empuja la unión en el no coaccionada valor al objeto modelo. El valor de la propiedad en el mando es coaccionado correctamente.

¿Cómo puedo conseguir la unión de empujar el coaccionado valor al objeto de modelo?

void Initialize()
{
    UIObject ui = new UIObject();
    ModelObject m = new ModelObject();
    m.P = 4;

    Binding b = new Binding("P");
    b.Source = m;
    b.Mode = BindingMode.TwoWay;
    Debug.WriteLine("SetBinding");
    // setting the binding will push the model value to the UI
    ui.SetBinding(UIObject.PProperty, b);

    // Setting the UI value will result in coercion but only in the UI.
    // The value pushed to the model through the binding is not coerced.
    Debug.WriteLine("Set to -4");
    ui.P = -4;

    Debug.Assert(ui.P == 0);
    // The binding is TwoWay, the DP value is coerced to 0.
    Debug.Assert(m.P == 0); // Not true. This will be -4. Why???
}

class UIObject : FrameworkElement
{
    public static readonly DependencyProperty PProperty =
        DependencyProperty.Register("P", typeof(int), typeof(UIObject), 
        new FrameworkPropertyMetadata(
            new PropertyChangedCallback(OnPChanged), 
            new CoerceValueCallback(CoerceP)));

    public int P
    {
        get { return (int)GetValue(PProperty); }
        set { SetValue(PProperty, value); }
    }

    private static void OnPChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Debug.WriteLine(typeof(UIObject) + ".P changed from " + e.OldValue + " to " + e.NewValue);
    }

    private static object CoerceP(DependencyObject sender, object value)
    {
        int p = (int)value;
        if (p < 0)
        {
            Debug.WriteLine(typeof(UIObject) + ".P coerced from " + p + " to 0");
            p = 0;
        }
        return p;
    }
}

class ModelObject
{
    private int p;
    public int P
    {
        get
        {
            Debug.WriteLine(this + ".P returned " + this.p);
            return this.p;
        }
        set
        {
            Debug.WriteLine(this + ".P changed from +" + this.p + " to " + value);
            this.p = value;
        }
    }
}
¿Fue útil?

Solución

No creo que la devolución de llamada coaccionar está destinado a ser una calle de dos vías. Una solución sería la de actualizar el valor del modelo de interior de la devolución de llamada coaccionar.

Otros consejos

Creo que esa es la idea de la coerción - valor correcto sobre la marcha sin provocar la modificación de cualesquiera otras dependencias. Puede utilizar el código de abajo en lugar de mecanismos de coerción nativas:

OnPChanged(/* ... */)
{
    // ...
    var coercedP = CoerceP(P);
    if (P != coercedP)
        P = coercedP;
    // ...
}

HTH.

Este es el método de extensión donde se establece el valor de objeto de destino

public static void SetTargetValue<T>(this FrameworkElement element, DependencyProperty dp, T value)
    {
        var binding = BindingOperations.GetBinding(element, dp);
        if (binding == null) return;
        var name = binding.Path.Path;
        var splits = name.Split('.');
        var target = element.DataContext;
        for (var i = 0; i < splits.Length; i++)
        {
            PropertyInfo property;
            if (i == splits.Length - 1)
            {
                property = target.GetType().GetProperty(splits[i]);
                property.SetValue(target, value);
            }
            else
            {
                property = target.GetType().GetProperty(splits[i]);
                target = property.GetValue(target);
            }
        }
    }

Por lo tanto, en este método, el uso de unión, se puede establecer el valor de la fuente. De la fuente de cource camino puede tener un montón de nombres - Property1.Property2.Property3 y etc. En el método de coaccionar sólo necesitan llamar a este método:

private static object CoerceProperty(DependencyObject d, object baseValue)
    {
        if (!Check)
        {
            var sender = (FrameworkElement)d;
            sender.SetTargetValue(MyPropertyProperty, myValue);
            return needValue;
        }
        return baseValue;
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top