2012-04-16 17 views
8

después de leer this article, una tiene el siguiente código en mi clase PersonViewModel:Generando propiedades de ViewModel en 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"); 
     } 
    } 
} 

también tengo CountryDomiciled, CountryPassport y LegalJurisdiction, todos con el mismo formato. Del mismo modo, tengo muchas propiedades String, todas las cuales comparten su formato.

¡Esto da como resultado muchos códigos samey! Sin embargo, no puedo descifrar cómo hacer esto más conciso.

¿Existe alguna forma mejor de generar estas propiedades que las mantenga fuertemente tipadas?

+1

+1 por acuñar la frase "código repetitiva"! Voy a tener que usar ese. – Zannjaminderson

+2

Si está utilizando C# 5, puede deshacerse de algún código repetitivo con nuevos atributos.Vea aquí: http://bhrnjica.net/2012/03/18/new-feature-in-c-5-0-callermembername/ – Vlad

+0

@Vlad Gracias, esto parece limpio. En este caso, aunque todo C# 5 me da la capacidad de eliminar la cadena de 'OnPropertyChanged', ¿verdad? – Oliver

Respuesta

4

ACTUALIZACIÓN: NotifyPropertyWeaver es obsoleto y continúa su vida como PropertyChanged.Fody. Esta es una forma súper genial para resolver este problema. Es una solución de solo tiempo de compilación.

Aquí hay algo que le ahorrará código y problemas: NotifyPropertyWeaver

Utilizando lo anterior, se puede poner en práctica sus propiedades sin ningún código relacionado INotifyPropertyChanged, y un paso de generación manejará el cableado para usted.

Es un proyecto simple incluir (también disponible a través de Nuget) que inyectará automáticamente las devoluciones de llamadas OnPropertyChanged en las propiedades de cualquier clase que implemente INotifyPropertyChanged. Lo hace en tiempo de compilación (así que no hay tiempo de ejecución) y tu código puede tener propiedades implementadas automáticamente (excepto en tu caso, donde estás usando un objeto de respaldo separado).

Incluso incluye la comprobación de igualdad de valores, por lo que cubre la lógica completa. No lo he probado con propiedades implementadas manualmente, pero vale la pena echarle un vistazo.

EDIT: Lo he probado ahora, y funciona bien: una propiedad implementada manualmente "solo funcionará".

+0

Autor comentó esto a mi respuesta: "Sin embargo, preferiría una forma que mantenga la funcionalidad compartida en un solo lugar, si es posible, en lugar de clonarla para cada propiedad" . ¿Cómo responde tu respuesta a esta necesidad? Sin embargo, no votaré por tu publicación. – EvAlex

+0

@EvAlex: el requisito de "mantenerlo en un solo lugar" es reducir el costo de mantenimiento, como ocurre con todo el código. Pero con un enfoque de AOP no habrá código que deba ser mantenido por el desarrollador. Cómo el AOP inyecta el código necesario no tiene ninguna consecuencia en este sentido. –

0

¿No ha intentado utilizar los fragmentos de código de Visual Studio como prop o propfull? Simplemente escríbalo y presione la tecla Tab dos veces. El problema es propfull, el fragmento no genera Evento registrado en PropertyChanged.

Pero en realidad debería haber trozos de terceros para dicha tarea. Esto es lo que encontré: property snippet with INPC

+0

Gracias, no los había visto antes, parecen realmente pulcros. Sin embargo, preferiría una forma que mantenga la funcionalidad compartida en un solo lugar, si esto es posible, en lugar de clonarla para cada propiedad. – Oliver

+0

Esto no resuelve el problema en la pregunta, ya que todavía tiene que duplicar el código. –

+0

@Dan Puzey No hubo nada sobre la duplicación de código en la pregunta. "¿Hay alguna forma mejor de generar estas propiedades que las mantenga fuertemente tipadas?". Respondí: "Hay: fragmentos de código". – EvAlex

1

No conozco ninguna forma incorporada, pero podría grabar una macro que generará el código para usted. La forma más fácil de hacerlo es simplemente comenzar a grabar una macro, luego crear lo que quieras usando solo el teclado (puede encontrar una lista de atajos de teclado útiles here)

Por ejemplo, tengo uno que genera la versión pública de una propiedad, así que todo lo que tengo que escribir es private string _someValue; y presiono mi macro, y generará la propiedad pública junto con la notificación de cambio de propiedad.

Dicho esto, tenga en cuenta que es perfectamente válido en MVVM exponer todo el Modelo a la Vista por simplicidad y conveniencia. Entonces, en lugar de exponer cada una de las propiedades del Modelo por separado, simplemente crearía una sola propiedad para su objeto Modelo.

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

y se unen a las propiedades del modelo así:

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

No es realmente lo que busca, sino como un aparte se puede guardar dos líneas por propiedad mediante la inversión de la prueba de la lógica:

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

+1 para la implementación más eficiente. –

+0

Haría +1 a esto, pero en realidad no responde la pregunta, así que no voy a hacerlo. Sería mejor como un comentario. – Rachel

+0

De acuerdo, nunca fue una respuesta completa. Han subido la votación de Dan para llegar a la cima. – GazTheDestroyer

8

Uso el fragmento para Visual Studio, que genera propiedades con almacenamiento de respaldo y generación de eventos para mí. Simplemente crear el archivo XML con el nombre propchanged (u otro nombre, si lo desea) y el siguiente contenido:

<?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> 

Y ponerlo a la carpeta C:\Users\YourName\Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets\.

A continuación, heredo mis ViewModels de algún ViewModelo base, que implementa la interfaz INotifyPropertyChanged y proporciona el método protegido OnPropertyChanged para generar el evento `PropertyChanged '.

public class ViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

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

Ahora cuando se escribe propchanged en Visual Studio, se le preguntará por tipo de propiedad y el nombre, y generar código para usted.

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

ACTUALIZACIÓN:

Otra opción es la generación de código por el marco AOP como PostSharp. En este caso, el código se generará y agregará durante la compilación (por lo tanto, sus clases permanecerán limpias). Here es ejemplo de implementación INotifyProperty cambiar a través PostSharp atributos:

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

+1 por fragmento sobre marcos de generación de MSIL complicados. ¡Manténlo simple stoopid! –

+1

Fragmento excelente que se puede ajustar según las necesidades individuales + – usefulBee

1

Para obtener una referencia "fuerte-tipada" al nombre de la propiedad (que se requiere para habilitar la refactorización), puede usar expresiones. Ponga el siguiente método, tal vez en una clase base para sus 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)); 
} 

En sus ViewModels, a continuación, será capaz de hacer lo siguiente:

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

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

Ahora, los nombres de propiedades refactorización son automáticamente recogido ya que la referencia es contra la propiedad real.

Esto resuelve el problema de los nombres de propiedades de codificación, aunque todavía requiere las 4-5 líneas de código repetitivo. Los enfoques orientados a aspectos como notifypropertyweaver y PostSharp realmente eliminan todos los codificación manual en los viewmodels.

Cuestiones relacionadas