onpropertychanged implementar implement c# .net static inotifypropertychanged

c# - implementar - inotifypropertychanged xamarin forms



INotifyPropertyChanged y propiedades estáticas (3)

Me estoy atando en un nudo por un simple problema. Tengo una clase que implementa INotifyPropertyChanged . Algunos de los captadores de propiedades de la instancia utilizan propiedades estáticas y, por lo tanto, sus valores pueden cambiar si la propiedad estática cambia. Aquí hay un ejemplo simplificado.

class ExampleClass : INotifyPropertyChanged { private static int _MinimumLength = 5; public static int MinimumLength { get { return _MinimumLength; } set { if (_MinimumLength != value) { _MinimumLength = value; //WHAT GOES HERE } } } private int _length = -1; public int length { get { return (_length > _MinimumLength) ? _length : _MinimumLength; } set { var oldValue = (_length > _MinimumLength) ? _length : _MinimumLength; if (_length != value) { _length = value; var newValue = (_length > _MinimumLength) ? _length : _MinimumLength; if (newValue != oldValue) { OnPropertyChanged("length"); } } } } public event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }

Claramente, si la propiedad estática MinimumLength cambia, entonces la length la propiedad de cada instancia también puede cambiar. Pero, ¿cómo debería la propiedad estática señalar el posible cambio a las instancias? No puede llamar a OnPropertyChanged ya que no es estático.

Podría mantener una lista a nivel de clase de todas las instancias y llamar a un método en cada una, pero de alguna manera eso se siente como una exageración. O podría extraer las propiedades estáticas en una clase singleton pero, lógicamente, viven en el nivel de clase. ¿Hay un patrón establecido para esto o debería estar pensando en esto de manera diferente?


Me enfrenté al mismo problema. Aquí está la solución que he puesto en marcha.

public class ZoomDataVm : ModelBase { public ZoomDataVm() { // initialise the zoom } private double _zoomLevel; public double ZoomLevel { get { return _zoomLevel; } set { if (_zoomLevel != value) { _zoomLevel = value; RaisePropertyChanged(() => ZoomLevel); // // persist zoom info } } } } public class ZoomVm : ModelBase { public static ZoomDataVm _instance; static ZoomVm() { _instance = new ZoomDataVm(); } public ZoomDataVm Instance { get { return _instance; } } }

Entonces lo uso en el XAML así.

<StackPanel> <StackPanel.Resources> <screenControls:ZoomVm x:Key="ZoomVm" /> </StackPanel.Resources> <TextBlock Text="{Binding ElementName=uiScaleSliderContainer, Path=Tag}" Foreground="White" Margin="0,0,20,0" /> <Control Name="uiScaleSliderContainer" Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Left" Tag="{Binding Source={StaticResource ZoomVm}, Path=Instance.ZoomLevel}"> <Control.Template> <ControlTemplate> <Slider Orientation="Horizontal" Width="400" x:Name="uiScaleSlider" ToolTip="Zoom" Value="{Binding ElementName=uiScaleSliderContainer, Path=Tag}" Minimum="0.1" Maximum="2" TickFrequency="0.1" IsSnapToTickEnabled="True"> </Slider> </ControlTemplate> </Control.Template> </Control> </StackPanel>


Puede usar la técnica mencionada en la propiedad estática de enlace y la implementación de INotifyPropertyChanged, pero también puede generar una notificación de "longitud", por ejemplo

class ExampleClass : INotifyPropertyChanged { private static int _MinimumLength = 5; public int MinimumLength { get { return _MinimumLength; } set { if (_MinimumLength != value) { _MinimumLength = value; OnPropertyChanged("MinimumLength"); OnPropertyChanged("length"); } } } ... }


Si está dispuesto a mantener ese diseño, entonces me gustaría una solución como la siguiente:

public static int MinimumLength { get { return _MinimumLength; } set { if (_MinimumLength != value) { _MinimumLength = value; OnGlobalPropertyChanged("MinimumLength"); } } } static event PropertyChangedEventHandler GlobalPropertyChanged = delegate { }; static void OnGlobalPropertyChanged(string propertyName) { GlobalPropertyChanged( typeof (ExampleClass), new PropertyChangedEventArgs(propertyName)); } public ExampleClass() { // This should use a weak event handler instead of normal handler GlobalPropertyChanged += this.HandleGlobalPropertyChanged; } void HandleGlobalPropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) { case "MinimumLength": if (length > MinimumLength) length = MinimumLength; break; } }

Esto es prácticamente equivalente a mantener una lista de instancias, pero me parece más fácil de mantener y más claro. Además, realmente necesita usar una estrategia de controlador de eventos débil, de lo contrario, sus instancias no se recolectarán como basura porque siempre estarán asociadas con el evento estático que actúa como una raíz GC.

Puedes leer más sobre los manejadores de eventos débiles en las siguientes publicaciones del blog (que fueron escritas por mí, por lo que estoy sesgado):

Controladores de eventos débiles .NET - Parte I

Controladores de eventos débiles .NET - Parte I

En una nota no relacionada, su código que actualmente está activando la propiedad cambió cuando, de hecho, el valor de la propiedad no cambió. Por ejemplo:

  1. Establezca MinimumLength en 5;
  2. Establecer la longitud a 10; (el evento se dispara porque el valor cambia de 0 a 5 predeterminado)
  3. Establecer la longitud a 11; (el evento se dispara pero no debería debido a que la longitud aún es 5)