Frage

Ich habe eine Kontrolle mit einem DependencyProperty mit einem CoerceValueCallback. Diese Eigenschaft ist gebunden an eine Eigenschaft auf einem Modellobjekt.

Wenn auf einen Wert die Steuer-Eigenschaft, den Zwang bewirkt, dass die Bindung drückt den uncoerced Wert auf das Modellobjekt. Der Eigenschaftswert auf der Steuerung richtig dazu gezwungen.

Wie erhalte ich die Bindung der gezwungen Wert auf das Modellobjekt drücken?

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;
        }
    }
}
War es hilfreich?

Lösung

Das glaube ich nicht der nötige Rückruf eine Einbahnstraße sein gemeint ist. Eine Abhilfe wäre, den Wert des Modells zu aktualisieren innerhalb des coerce Rückruf.

Andere Tipps

Ich denke, das ist die ganze Idee des Zwangs - richtigen Wertes im laufenden Betrieb ohne Änderung von anderen Abhängigkeiten auslöst. Sie können unten statt nativen Zwang Mechanismen den Code verwenden:

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

HTH.

Hier ist Extension-Methode, wo man Wert auf Zielobjekt gesetzt

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

Also, in diesem Verfahren unter Verwendung von Bindung, können Sie Wert auf Quelle eingestellt. Pfad kann viele Namen haben cource Quelle - Property1.Property2.Property3 und etc. In coerce Methode müssen Sie nur diese Methode aufrufen:

private static object CoerceProperty(DependencyObject d, object baseValue)
    {
        if (!Check)
        {
            var sender = (FrameworkElement)d;
            sender.SetTargetValue(MyPropertyProperty, myValue);
            return needValue;
        }
        return baseValue;
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top