2012-04-16 13 views
8

dopo aver letto this article, un avere il seguente codice nella mia classe PersonViewModel:Creazione rapida delle proprietà ViewModel in wpf?

public Jurisdiction CountryResidence 
{ 
    get 
    { 
     return Model.CountryResidence; 
    } 
    set 
    { 
     if (Model.CountryResidence == value) 
      return; 
     else 
     { 
      Model.CountryResidence = value; 
      base.OnPropertyChanged("CountryResidence"); 
     } 
    } 
} 

public Jurisdiction CountryBirth 
{ 
    get 
    { 
     return Model.CountryBirth; 
    } 
    set 
    { 
     if (Model.CountryBirth == value) 
      return; 
     else 
     { 
      Model.CountryBirth = value; 
      base.OnPropertyChanged("CountryBirth"); 
     } 
    } 
} 

Ho anche CountryDomiciled, CountryPassport e LegalJurisdiction, tutti con lo stesso formato. Allo stesso modo, ho un sacco di proprietà String, che condividono tutti il ​​loro formato.

Questo risulta in un sacco di codici uguali! Tuttavia, non riesco a capire come renderlo più conciso.

C'è un modo migliore per generare queste proprietà che le mantiene fortemente digitate?

+1

+1 per aver coniato la frase "Codice monotono"! Dovrò usare quello. – Zannjaminderson

+2

Se si utilizza C# 5, è possibile sbarazzarsi di alcuni codici standard con nuovi attributi.Vedi qui: http://bhrnjica.net/2012/03/18/new-feature-in-c-5-0-callermembername/ – Vlad

+0

@Vlad Grazie, questo sembra pulito. In questo caso però tutto il C# 5 mi dà la possibilità di rimuovere la stringa da "OnPropertyChanged", giusto? – Oliver

risposta

4

UPDATE: NotifyPropertyWeaver è obsoleto e continua la sua vita come PropertyChanged.Fody. Questo è un modo assolutamente fantastico per risolvere questo problema. È una soluzione di sola compilazione.

ecco qualcosa che vi farà risparmiare codice e difficoltà: NotifyPropertyWeaver

Utilizzando quanto sopra, è possibile implementare le vostre proprietà senza alcun codice correlato INotifyPropertyChanged, e un passaggio di generazione gestirà il cablaggio per voi.

È un semplice progetto che include (disponibile anche tramite Nuget) che inserisce automaticamente i callback OnPropertyChanged nelle proprietà di qualsiasi classe che implementa INotifyPropertyChanged. Lo fa in fase di compilazione (quindi nessun hit di runtime) e il tuo codice può avere solo proprietà auto-implementate (tranne nel tuo caso, dove stai usando un oggetto di backup separato).

Include anche il controllo di uguaglianza dei valori, quindi copre la logica completa. Non l'ho testato con proprietà implementate manualmente, ma vale la pena di provarlo.

EDIT: L'ho provato ora e funziona perfettamente: una proprietà implementata manualmente "funzionerà".

+0

Autore ha commentato questo alla mia risposta: "Tuttavia, preferirei un modo che mantiene la funzionalità condivisa in un unico posto, se questo è possibile, piuttosto che clonarlo per ogni proprietà" . In che modo la tua risposta risolve questo bisogno? Comunque non voterò per il tuo post. – EvAlex

+0

@EvAlex - il requisito di "tenerlo in un posto" è quello di ridurre i costi di manutenzione, come avviene con tutto il codice. Ma con un approccio AOP non ci sarà codice che deve essere mantenuto dallo sviluppatore. Il modo in cui l'AOP inietta il codice necessario non ha alcuna conseguenza a questo riguardo. –

0

Non hai provato a utilizzare frammenti di codice di Visual Studio come prop o propfull? Basta digitare e premere il tasto Tab due volte. Il problema è lo snippet propfull non aumenta l'evento PropertyChanged.

Ma in realtà ci dovrebbero essere snippet di terze parti per tale compito. Ecco cosa ho trovato: property snippet with INPC

+0

Grazie, non li ho mai visti prima - sembrano davvero puliti. Tuttavia, preferirei un modo che mantenga la funzionalità condivisa in un posto, se possibile, piuttosto che clonarla per ogni proprietà. – Oliver

+0

Questo non risolve il problema nella domanda, poiché è ancora necessario duplicare il codice. –

+0

@Dan Puzey Nella questione non c'era nulla di duplicazione del codice. "C'è un modo migliore per generare queste proprietà che le mantiene fortemente digitate?". Ho risposto: "C'è: frammenti di codice". – EvAlex

1

Non so di alcun modo integrato, ma è possibile registrare una Macro che genererà il codice per voi. Trovo il modo più semplice per farlo è quello di avviare solo la registrazione di una macro, quindi si crea quello che volete utilizzando la tastiera solo (è possibile trovare un elenco di scorciatoie da tastiera a portata di mano here)

Ad esempio, ho uno che genera il versione pubblica di una proprietà, quindi tutto quello che devo digitare è private string _someValue; e colpire la mia macro, e genererà la proprietà pubblica insieme alla notifica di modifica della proprietà.

Detto questo, tenere presente che è perfettamente valido in MVVM esporre l'intero modello alla vista per semplicità e praticità. Quindi, invece di esporre separatamente ciascuna proprietà del modello, dovresti semplicemente creare una singola proprietà per il tuo oggetto Modello.

public Model SomeModel 
{ 
    get 
    { 
     return Model; 
    } 
    set 
    { 
     if (Model == value) 
      return; 
     else 
     { 
      Model= value; 
      base.OnPropertyChanged("SomeModel"); 
     } 
    } 
} 

e si legano alle proprietà del modello come questo:

<TextBox Text="{Binding SomeModel.SomeProperty}" /> 
2

Non proprio quello che stai cercando, ma come un a parte è possibile salvare due linee per casa invertendo il test logica:

public Jurisdiction CountryResidence 
{ 
    get 
    { 
     return Model.CountryResidence; 
    } 
    set 
    { 
     if (Model.CountryResidence != value) 
     { 
      Model.CountryResidence = value; 
      base.OnPropertyChanged("CountryResidence"); 
     } 
    } 
} 
+0

+1 per l'implementazione più efficiente. –

+0

Vorrei fare +1 su questo, ma in realtà non risponde alla domanda, quindi non lo farò. Sarebbe meglio come commento. – Rachel

+0

D'accordo, mai inteso come una risposta completa. Ho svaligiato Dan per farcela. – GazTheDestroyer

8

Io uso lo snippet per Visual Studio, che genera proprietà con archiviazione di backup e event raising per me. È sufficiente creare il file XML con il nome propchanged (o un altro nome, se lo si desidera) e seguente contenuto:

<?xml version="1.0" encoding="utf-8" ?> 
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 
    <CodeSnippet Format="1.0.0"> 
    <Header> 
     <Title>propchanged</Title> 
     <Shortcut>propchanged</Shortcut> 
     <Description>Code snippet for property (with call to OnPropertyChanged) and backing field</Description> 
     <Author>lazyberezovsky</Author> 
     <SnippetTypes> 
     <SnippetType>Expansion</SnippetType> 
     </SnippetTypes> 
    </Header> 
    <Snippet> 
     <Declarations> 
     <Literal> 
      <ID>type</ID> 
      <ToolTip>Property type</ToolTip> 
      <Default>string</Default> 
     </Literal> 
     <Literal> 
      <ID>property</ID> 
      <ToolTip>Property name</ToolTip> 
      <Default>MyProperty</Default> 
     </Literal> 
     <Literal> 
      <ID>field</ID> 
      <ToolTip>The variable backing this property</ToolTip> 
      <Default>myVar</Default> 
     </Literal> 
     </Declarations> 
     <Code Language="csharp"> 
     <![CDATA[private $type$ $field$; 

    public $type$ $property$ 
    { 
     get { return $field$;} 
     set 
    { 
     if ($field$ == value) 
      return; 

     $field$ = value; 
     OnPropertyChanged("$property$"); 
    } 
    } 
    $end$]]> 
     </Code> 
    </Snippet> 
    </CodeSnippet> 
</CodeSnippets> 

E metterlo nella cartella C:\Users\YourName\Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets\.

Successivamente, eredito il mio ViewModels da qualche base ViewModel, che implementa l'interfaccia INotifyPropertyChanged e fornisce il metodo protetto OnPropertyChanged per generare l'evento `PropertyChanged '.

public class ViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName); 
    } 
} 

Ora, quando si digita propchanged in Visual Studio, vi verrà chiesto per tipo di proprietà e il nome, e generare codice per voi.

public class PersonViewModel : ViewModel 
{ 
    // type here 'propchanged' (or other shortcut assigned for snippet) 
} 

UPDATE:

Un'altra opzione genera codice framework AOP come PostSharp. In questo caso il codice verrà generato e aggiunto durante la compilazione (quindi le tue classi rimarranno pulite). Here è esempio di implementazione INotifyProperty modificata tramite PostSharp attributi:

[Notify] 
public class PersonViewModel 
{ 
    public Jurisdiction CountryResidence { get; set; } 
    public Jurisdiction CountryBirth { get; set; } 
} 
+1

+1 per lo snippet su complicati framework di generazione di MSIL. Mantienilo semplice! –

+1

Frammento eccellente che può essere regolato in base alle esigenze individuali + – usefulBee

1

Per ottenere un riferimento "strong-typed" al nome della proprietà (necessario per abilitare il refactoring), è possibile utilizzare le espressioni. Mettere il seguente metodo, forse in una classe base per le vostre ViewModels:

protected void RaisePropertyChanged<T>(Expression<Func<T>> property) 
{ 
    var handler = PropertyChanged; 
    if (handler == null) return; 

    var propertyName = NotifyPropertyChangedHelper.GetPropertyNameFromExpression(property); 
    handler(sender, new PropertyChangedEventArgs(propertyName)); 
} 

Nei tuoi ViewModels, sarete quindi in grado di effettuare le seguenti operazioni:

public Jurisdiction CountryResidence 
{ 
    get { return Model.CountryResidence; } 
    set 
    {   
     if (Model.CountryResidence == value) 
      return; 

     Model.CountryResidence = value; 
     OnPropertyChanged(() => CountryResidence); 
    } 
} 

Ora, i nomi delle proprietà refactoring sono automaticamente raccolto dal momento che il riferimento è contro la proprietà effettiva.

Questo risolve il punto dolente dei nomi delle proprietà di hardcoding, sebbene richieda ancora le 4-5 righe del codice boilerplate. Approcci orientati all'aspetto come notifypropertyweaver e PostSharp rimuovono davvero tutta la codifica manuale nei modelli viewmodels.

Problemi correlati