2009-02-05 8 views
10

Possiedo un controllo con DependencyProperty con CoerceValueCallback. Questa proprietà è associata a una proprietà su un oggetto modello.Come faccio a rendere vincolante Binding rispetto alla coercizione del valore DependencyProperty?

Quando si imposta la proprietà di controllo su un valore che provoca la coercizione, Binding spinge il valore non utilizzato all'oggetto del modello. Il valore della proprietà sul controllo è forzato correttamente.

Come si ottiene la rilegatura per spingere il valore forzato all'oggetto modello?

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

risposta

1

Non credo che il richiamo coercitivo sia destinato a essere una strada a doppio senso. Una soluzione alternativa sarebbe aggiornare il valore del modello all'interno del richiamo coercitivo.

2

Penso che sia tutta l'idea della coercizione: correggere il valore al volo senza attivare la modifica di altre dipendenze. È possibile utilizzare il codice riportato di seguito anziché i meccanismi di coercizione nativa:

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

HTH.

+3

Sono un po 'confuso .. perché si vuole costringere un valore ma hanno ancora eg Gli elementi della GUI associati alla proprietà mostrano un valore non coercitivo? La GUI mostrerà quindi qualcosa che non è vero ... –

+0

Il pensiero è che se si applica la coercizione su entrambi i lati del legame, allora non ci sarebbe nulla di sbagliato con la GUI vincolata o qualunque cosa sia limitata a. Topicstarter sta cercando di forzare il valore sul lato ricevente (ad esempio sul lato GUI). – archimed7592

0

Ecco metodo di estensione in cui si imposta il valore su un oggetto bersaglio

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

Quindi, in questo metodo, utilizzando vincolante, è possibile impostare il valore di fonte. Di fonte cource percorso può avere un sacco di nomi - Property1.Property2.Property3 ed ecc Nel metodo di costringere il necessario solo chiamare questo metodo:

private static object CoerceProperty(DependencyObject d, object baseValue) 
    { 
     if (!Check) 
     { 
      var sender = (FrameworkElement)d; 
      sender.SetTargetValue(MyPropertyProperty, myValue); 
      return needValue; 
     } 
     return baseValue; 
    }