2009-02-05 10 views
10

Tengo un control con DependencyProperty con CoerceValueCallback. Esta propiedad está vinculada a una propiedad en un objeto modelo.¿Cómo hago que la vinculación respete la coerción de valores de DependencyProperty?

Al establecer la propiedad de control a un valor que hace que la coacción empuja la unión del sin coacción valor al objeto modelo. El valor de la propiedad en el control se coacciona correctamente.

¿Cómo obtengo que la vinculación empuje el forzado valor al objeto 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; 
     } 
    } 
} 

Respuesta

1

No creo que la llamada forzada sea una calle de doble sentido. Una solución alternativa sería actualizar el valor del modelo dentro de la devolución de llamada coercitiva.

2

Creo que esa es la idea de la coerción: corregir el valor sobre la marcha sin activar la modificación de 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.

+3

Estoy un poco confundido .. ¿por qué quiere coaccionar un valor pero todavía tiene, por ejemplo Los elementos GUI vinculados a la propiedad muestran un valor no forzado? La GUI mostrará algo que no es verdad ... –

+0

La idea es que si aplicas la coerción en ambos lados de la vinculación, entonces no habría nada de malo con la GUI enlazada o lo que sea que esté limitado. Topicstarter está tratando de forzar el valor en el lado receptor (por ejemplo, en el lado de la GUI). – archimed7592

0

Aquí es 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 coaccionar sólo tiene que 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; 
    } 
Cuestiones relacionadas