2009-09-11 9 views
7

Quindi sto lavorando al mio primo progetto WPF e mi piace quello che vedo finora. C'era più di curva di apprendimento di quello che mi aspettavo, ma tuttavia WPF è piuttosto interessante. Tuttavia, sto combattendo un po 'con i concetti di associazione dei dati. Una domanda specifica che ho è: come posso rendere sicuro il refact delle dichiarazioni di binding dei dati? Considera questo esempio.Come si rende sicuro il refact dei binding di dati WPF?

public class MyDataObject 
{ 
    public string FooProperty { get; set; } 
} 

void Bind() 
{ 
    var gridView = myListView.View as GridView; 
    gridView.Columns.Clear(); 
    gridView.Columns.Add(
    new GridViewColumn() 
     { 
     Header = "FooHeader", 
     DisplayMember = new Binding("FooProperty") 
     } 
    ); 
    List<MyDataObject> source = GetData(); 
    myListView.ItemsSource = source; 
} 

Che cosa succede se rinominare la FooProperty sul mio oggetto dati su qualcos'altro? L'associazione dei dati non sarà valida e non riceverò un errore di compilazione poiché l'associazione è stata dichiarata solo tramite testo. C'è un modo per rendere il legame un po 'più sicuro per il refactoring?

risposta

3

Si potrebbe usare un'espressione lambda per esprimere il nome della proprietà, piuttosto che utilizzare direttamente il nome:

protected static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression) 
    { 
     if (expression.NodeType == ExpressionType.Lambda && expression.Body.NodeType == ExpressionType.MemberAccess) 
     { 
      PropertyInfo prop = (expression.Body as MemberExpression).Member as PropertyInfo; 
      if (prop != null) 
      { 
       return prop.Name; 
      } 
     } 
     throw new ArgumentException("expression", "Not a property expression"); 
    } 

usereste in quel modo:

... 
DisplayMember = new Binding(GetPropertyName((MyDataObject o) => o.FooProperty)) 
... 

Ok, è un po 'prolisso ... Se vuoi qualcosa di più breve, puoi anche creare un metodo di supporto:

public Binding CreateBinding<TSource, TResult>(Expression<Func<TSource, TResult>> expression) 
{ 
    return new Binding(GetPropertyName(expression)) 
} 

... 
DisplayMember = CreateBinding((MyDataObject o) => o.FooProperty) 
... 

Che w ay, il refactoring dovrebbe funzionare bene se si rinomina la proprietà (tranne che nel XAML ovviamente ...)

+0

Molto intelligente. Sì, lo xaml sarebbe ancora un problema, ma almeno nel mio scenario immediato devo costruire dinamicamente le colonne comunque, quindi non mi interessa al momento. Grazie! –

0

È possibile utilizzare la riflessione per determinare i nomi della proprietà. Ovviamente, questo è problematico se si hanno più di un binding per classe, quindi magari si possono usare anche attributi personalizzati (che sono disponibili anche tramite reflection) per ottenere 'suggerimenti' sul corretto campo di binding a cui deve essere associata la proprietà denominata.

Molto bene potrebbe finire per riposizionare la stringa magica non rifattabile in un'altra parte dell'applicazione, tuttavia, non posso dire di averlo provato e farlo funzionare.

+0

Il refactoring è qualcosa che si verifica in fase di progettazione, mentre la riflessione si verifica in fase di esecuzione. (In realtà nella lingua 'io', il refactoring può accadere in fase di esecuzione, ma questa è un'altra storia!) –

+0

Ovviamente, ma come ho capito la domanda, il refactoring non catturerebbe la "stringa magica" di FooProperty nell'associazione, quindi la proprietà cambierebbe e il legame non lo farebbe; ottenendo la stringa giusta in fase di esecuzione tramite la riflessione, stai sempre guardando il mondo più recente e non dipende dal fatto di aver cambiato tutte le tue costanti. – Mikeb

+0

@Mikeb - dipende da quale strumento di refactoring si usa. –

2

Il refactoring si basa sul supporto dello strumento che riconosce quando un particolare simbolo nel codice (C#, XAML, config ecc ...) rappresenta l'identificatore che viene rinominato.

Nell'esempio si dà, la stringa letterale "FooProperty" non potrebbe essere 100% interpretata come facente MyDataObject senza particolare conoscenza del funzionamento interno di GridView e per estensione tutti gli altri tipi di WPF e altri quadri.

Tuttavia, in un DataTemplate, è possibile essere sicuri al 99%:

<DataTemplate DataType="{x:Type local:MyDataObject}"> 
    <TextBlock Text="{Binding Path=FooProperty}" /> 
</DataTemplate> 

Io uso (e giuro da) un plugin IDE chiamato ReSharper (aka R #) che è un molto intelligente su questi tipi di cose. Se si rinomina FooProperty, R # rinomina automaticamente la proprietà.

Nel tuo esempio, se si dovesse rinominare la proprietà, R # sarebbe ancora utile. Trova tutte le occorrenze della stringa in letterali (il tuo caso) e commenti (molto utile se hai commentato qualche codice e potresti rimproverarlo in un secondo momento). Ti viene fornita una vista ad albero che mostra ogni letterale nel contesto, e puoi selezionare/deselezionare singoli usi/file/cartelle/progetti prima di procedere.

Se il budget lo consente, ottieni R #. Se il tuo budget non lo consente, scarica una versione di prova e alla fine di essa il tuo budget troverà spazio. Assicurati di stampare una copia dei tasti di scelta rapida per migliorare la tua esperienza di apprendimento.

+0

Buona raccomandazione. –

Problemi correlati