in

dotNet Umbria

Il primo User Group in Umbria sul mondo .Net

Articoli

Articoli vari degli iscritti a DotNetUmbria

WPF Invalidate Binding

Il binding di WPF è molto reattivo grazie a tutta la struttura di DependencyObjects e DependencyProperties a cui si appoggia. Per questo motivo lavorando con WPF molto spesso non ci dobbiamo preoccupare di fare un refresh dell'interfaccia utente per visualizzare i dati aggiornati.

Può capitare tuttavia di dover mettere in binding alcune sorgenti dati che non utilizzano DependencyProperties e che nella loro struttura non implementano l'interfaccia INotifyPropertyChanged . In questi rari casi accade che l'interfaccia utente non è aggiornata con i dati perchè non è in grado di capire che i dati sono stati modificati in qualche modo. Dobbiamo essere quindi noi a forzare il refresh.

Vediamo quali strumetni abbiamo a disposizione. Viene sicuramente in nostro aiuto la classe statica BindingOperations, la quale ci permette di interrogare la struttura ad oggetti dell'interfaccia utente e capire se le proprietà degli oggetti stessi sono in binding oppure no.

image

 

BindingOperations ci restituisce oggetti di tipo BindingExpression che sono di fatto il collegamento tra il target e la sorgente dati.

image

Possiamo utilizzare il metodo UpdateTarget per forzare la lettura dei dati ed un refresh dell'interfaccia utente.


Come facciamo tuttavia da codice a utilizzare questo metodo senza vincolare la grafica a delle strutture fisse di binding ?
Mi spiego meglio: Se utilizziamo questo metodo, dobbiamo conoscere esattamente quali sono i campi bindati per poter sollevare il binding e quindi vincoliamo lo sviluppo della parte grafica impedendo la modifica di template e di datatemplate.

Ci viene in aiuto un'altra classe molto importante: VisualTreeHelper.

image

Questa classe ci permette di navigare all'interno della VisualTree, ovvero all'interno degli oggetti renderizzati nell'interfaccia utente. Con un po' di reflection , e con l'aiuto di BidingOperations possiamo estrarre dalla VisualTree tutte le BindingExpressions ed invocare il metodo UpdateTarget.

Ecco il codice :

[code language="c#"]

 

private static void InvalidateBinding(DependencyObject objectbase)
{

  // Per ogni oggetto all'interno del ramo di visualtree
  for (int x = 0; x < VisualTreeHelper.GetChildrenCount(objectbase); x++)
  {

    // Leggo l'oggetto nodo
    DependencyObject obj = VisualTreeHelper.GetChild(ww, x) as DependencyObject;

    // Se è un DependencyObject
    if (obj != null)
    {

      // Cerco tutti i fields di
      foreach (FieldInfo finfo in obj.GetType().GetFields())
      {

        // Se il field trovato è una DependencyProperty allora può essere sottoposta a binding
        if (finfo.FieldType.Equals(typeof(DependencyProperty)))
        {

          // Verifico se è sottoposta a binding
          DependencyProperty dpvalue = (DependencyProperty)finfo.GetValue(obj);
          if (BindingOperations.IsDataBound(obj, dpvalue))
          {

            // Estraggo la BindingExpression
            BindingExpression expr = BindingOperations.GetBindingExpression(obj, dpvalue);
           

            // Sollevo il metodo di aggiornamento del binding.
            expr.UpdateTarget();
          }

          // Se il contenuto della DependencyProperty è un DependencyObject allora devo controllare anche tutte DP dell'oggetto contenuto nella DP corrente
          DependencyObject subdpobject = obj.GetValue(dpvalue) as DependencyObject;
          if (subdpobject != null)
            if (!(subdpobject is Visual))
            {
              foreach (FieldInfo subfinfo in subdpobject.GetType().GetFields())
              {
                DependencyProperty subdpvalue = (DependencyProperty)subfinfo.GetValue(subdpobject);
                if (BindingOperations.IsDataBound(subdpobject, subdpvalue))
                {
                  BindingExpression subexpr = BindingOperations.GetBindingExpression(subdpobject, subdpvalue);
                  subexpr.UpdateTarget();
                }
              }
            }
        }
      }

      // Rendo la funzione ricorsiva in modo da esplorare tutta la VisualTree
      InvalidateBinding(obj);
    }
  }
}

 

 

[/code]

Only published comments... Apr 10 2008, 04:18 PM by Paolo Possanzini

About Paolo Possanzini

Programmatore di vecchia data, mi sono appassionato a dotnet fin dalla prima versione. Mi interesso di programmazione, accesso ai dati, Sql Server.
Con Andrea abbiamo fondato TeamDev snc.

Scarica il mio Biglietto da visita
dotNet Umbria 2007-2008
Powered by Community Server (Commercial Edition), by Telligent Systems