2010-02-10 12 views
7

Supongamos que tengo Simple clase, que tienen un TotalPrice propiedad calculada, que puede ser obligado a WPF UIINotifyPropertyChanged y propiedad calculada

public class Order : INotifyPropertyChanged 
{ 
    public decimal ItemPrice 
    { 
    get { return this.itemPrice; } 
    set 
    { 
     this.itemPrice = value; 
     this.RaisePropertyChanged("ItemPrice"); 
     this.RaisePropertyChanged("TotalPrice"); 
    } 
    } 

    public int Quantity 
    { 
    get { return this.quantity; } 
    set 
    { 
     this.quantity= value; 
     this.RaisePropertyChanged("Quantity"); 
     this.RaisePropertyChanged("TotalPrice"); 
    } 
    } 

    public decimal TotalPrice 
    { 
    get { return this.ItemPrice * this.Quantity; }  
    } 
} 

¿Es una buena práctica para llamar RaisePropertyChanged ("TotalPrice") en el propiedades que afectan al cálculo de TotalPrice? ¿Cuál es la mejor manera de actualizar la propiedad TotalPrice? La otra versión de hacer esto, por supuesto, es cambiar propiedad como esta

public decimal TotalPrice 
{ 
    get { return this.ItemPrice * this.Quantity; } 
    protected set 
    { 
     if(value >= 0) 
      throw ArgumentException("set method can be used for refresh purpose only"); 

    } 
} 

y llame TotalPrice = -1 en vez de this.RaisePropertyChanged ("TotalPrice"); en otras propiedades. Por favor, sugerir soluciones mejor

Muchas gracias

+0

No creo que '' ItemPrice' y Cantidad 'debería ser responsable de subir' PropertyChanged' para 'TotalPrice'. Esto funcionará, pero ¿qué pasaría si 'ItemPrice' y' Quantity' estuvieran en otra clase? Entonces no podrías hacer esto, y tendrías que hacer esto de otra manera. He respondido esta pregunta en otra pregunta, donde la respuesta es la misma incluso si las propiedades estaban en la misma clase o si estaban en otras clases: http://stackoverflow.com/questions/43653750/raising-propertychanged-for- a-dependent-property-when-a-prerequisite-property-in-another-class – Jogge

Respuesta

4

Está bien que comprobar para ver si debe aumentar este evento, así de cualquier otro miembro que puede cambiar el valor, pero sólo lo hacen si realmente cambio la valor.

Se puede encapsular esto en un método:

private void CheckTotalPrice(decimal oldPrice) 
{ 
    if(this.TotalPrice != oldPrice) 
    { 
     this.RaisePropertyChanged("TotalPrice"); 
    } 
} 

Luego hay que llamar a que a partir de sus otros miembros mutantes:

var oldPrice = this.TotalPrice; 
// mutate object here... 
this.CheckTotalPrice(oldPrice); 
7

Otra solución es la que Robert Rossney propone en esta pregunta:

WPF INotifyPropertyChanged for linked read-only properties

puede crea te un mapa propiedad de dependencia (con sus ejemplos de código):

private static Dictionary<string, string[]> _DependencyMap = 
new Dictionary<string, string[]> 
{ 
    {"Foo", new[] { "Bar", "Baz" } }, 
}; 

y luego hacer esto en su OnPropertyChanged:

PropertyChanged(this, new PropertyChangedEventArgs(propertyName)) 
if (_DependencyMap.ContainsKey(propertyName)) 
{ 
    foreach (string p in _DependencyMap[propertyName]) 
    { 
     PropertyChanged(this, new PropertyChangedEventArgs(p)) 
    } 
} 

Incluso es posible adjuntar un atributo para atar la propiedad depende de la que depende en. Algo como:

[PropertyChangeDependsOn("Foo")] 
public int Bar { get { return Foo * Foo; } } 
[PropertyChangeDependsOn("Foo")] 
public int Baz { get { return Foo * 2; } } 

Todavía no he implementado los detalles del atributo. Será mejor que empiece a trabajar en eso ahora.

+0

Estaba buscando una biblioteca de código abierto que hiciera esto; podría escribirla yo mismo, pero alguien tiene que haberlo hecho ya. – BrainSlugs83

2

Si utiliza NotifyPropertyWeaver puede tener este código

public class Order : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public decimal ItemPrice { get; set; } 

    public int Quantity { get; set; } 

    public decimal TotalPrice 
    { 
     get { return ItemPrice*Quantity; } 
    } 
} 

y será compilado a esto.

public class Order : INotifyPropertyChanged 
{ 
    decimal itemPrice; 
    int quantity; 
    public event PropertyChangedEventHandler PropertyChanged; 

    public virtual void OnPropertyChanged(string propertyName) 
    { 
     var propertyChanged = PropertyChanged; 
     if (propertyChanged != null) 
     { 
      propertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public decimal ItemPrice 
    { 
     get { return itemPrice; } 
     set 
     { 
      if (itemPrice != value) 
      { 
       itemPrice = value; 
       OnPropertyChanged("TotalPrice"); 
       OnPropertyChanged("ItemPrice"); 
      } 
     } 
    } 

    public int Quantity 
    { 
     get { return quantity; } 
     set 
     { 
      if (quantity != value) 
      { 
       quantity = value; 
       OnPropertyChanged("TotalPrice"); 
       OnPropertyChanged("Quantity"); 
      } 
     } 
    } 

    public decimal TotalPrice 
    { 
     get { return ItemPrice*Quantity; } 
    } 
} 
0

¿Es una buena práctica para llamar RaisePropertyChanged ("TotalPrice") en las propiedades que afectan al cálculo TotalPrice?

No, no es escala, y es una pesadilla de mantenimiento.

https://github.com/StephenCleary/CalculatedProperties es mejor motor de fórmula a partir de ahora para MVVM (en mi opinión) que notifica acerca de los cambios de propiedades derivadas/calculados y es compatible con cualquier nivel de anidamiento

public decimal ItemPrice 
    { 
    get { return Property.Get(0m); } 
    set { Property.Set(value); } 
    } 

    public int Quantity 
    { 
    get { return Property.Get(0); } 
    set { Property.Set(value); } 
    } 

    public decimal TotalPrice 
    { 
    get { return Property.Calculated(() => ItemPrice * Quantity); }  
    } 
+0

Creo que la mejor manera en .net 4.5+ para llamar a nameof (Total) –

+0

No me referí a la cadena de código duro vs nameof() - el antipattern es que las propiedades de disparo (Quantity y ItemPrice) en el ejemplo original conocen sus usos en derivados propiedades aguas arriba. p.s. CalculatedProperties usa el atributo [CallerMemberName] para evitar los nombres de propiedad de código duro – KolA

+0

si usamos RaisePropertyChanged (nameof (TotalPrice)) que si se cambiará el nombre de la propiedad, el código no se compilará ... así que esto debería ser suficiente como –

Cuestiones relacionadas