using System; using System.ComponentModel; using System.Diagnostics; using Developpez.Dotnet.Windows.Service; namespace Developpez.Dotnet.Windows.ViewModel { /// /// Classe de base pour toutes les classes ViewModel (Vue-Modèle) dans le cadre du pattern MVVM /// Fournit le support pour la notification de changement des propriétés (interface INotifyPropertyChanged) /// et propose une propriété DisplayName. Cette classe est abstraite. /// /// Cette classe a été proposée par Josh Smith dans son article sur le pattern MVVM. public abstract class ViewModelBase : IDisposable, INotifyPropertyChanged { #region Constructeur /// /// Crée une nouvelle instance de ViewModelBase. Ce constructeur est protégé et ne peut /// être appelé que par les classes dérivées. /// protected ViewModelBase() { } #endregion // Constructeur #region Propriétés publiques /// /// Renvoie le nom convivial de cet objet. /// Les classes dérivées peuvent affecter une nouvelle valeur à cette propriété, /// ou modifier son implémentation pour déterminer la valeur à la demande /// public virtual string DisplayName { get; protected set; } #endregion // Propriétés publiques #region Utilitaires de débogage /// /// Avertit le développeur si cet objet n'a pas de propriété avec le nom spécifié. /// Cette méthode n'existe pas en version Release. /// /// Nom de la propriété [Conditional("DEBUG")] [DebuggerStepThrough] public void VerifyPropertyName(string propertyName) { // Vérifie que le nom de propriété correspond à une vraie // propriété publique d'instance de l'objet if (TypeDescriptor.GetProperties(this)[propertyName] == null) { string msg = string.Format(ExceptionMessages.BadPropertyName, propertyName); if (this.ThrowOnInvalidPropertyName) throw new Exception(msg); else Debug.Fail(msg); } } /// /// Indique si une exception doit être levée, ou si Debug.Fail est utilisé quand /// un nom de propriété incorrect est passé à la méthode VerifyPropertyName. /// La valeur par défaut est false, mais les classes dérivées peuvent modifier ce /// comportement. /// public virtual bool ThrowOnInvalidPropertyName { get; protected set; } #endregion // Utilitaires de débogage #region Membres de INotifyPropertyChanged /// /// Se produit quand la valeur d'une propriété de cet objet est modifiée /// public event PropertyChangedEventHandler PropertyChanged; /// /// Déclenche l'évènement PropertyChanged sur cet objet. /// /// La propriété dont la valeur a changé protected virtual void OnPropertyChanged(string propertyName) { this.VerifyPropertyName(propertyName); PropertyChangedEventHandler handler = this.PropertyChanged; if (handler != null) { var e = new PropertyChangedEventArgs(propertyName); handler(this, e); } } #endregion // Membres de INotifyPropertyChanged #region Membres de IDisposable /// /// Appelé pour libérer les ressources liées à cet objet /// public void Dispose() { this.OnDispose(); } /// /// Les classes dérivées peuvent redéfinir cette méthode pour effectuer /// des opérations de nettoyage, comme la suppression de gestionnaires d'évènement /// protected virtual void OnDispose() { } #if DEBUG /// /// Utile pour vérifier que les objets ViewModel sont correctement ramassés par le /// garbage collector. /// ~ViewModelBase() { string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode()); System.Diagnostics.Debug.WriteLine(msg); } #endif #endregion // Membres de IDisposable #region GetService /// /// Renvoie le service du type spécifié avec le nom spécifié /// /// Type du service /// Nom du service /// Le service demandé s'il existe. Sinon, une ServiceNotFoundException est levée. public virtual TService GetService(string name) { return ServiceLocator.Instance.GetService(name); } /// /// Renvoie le service sans nom du type spécifié /// /// Type du service /// Le service demandé s'il existe. Sinon, une ServiceNotFoundException est levée. public TService GetService() { return GetService(null); } #endregion } /// /// Classe de base pour un ViewModel qui expose le modèle via une propriété fortement typée /// /// Type du modèle public abstract class ViewModelBase : ViewModelBase { /// /// Renvoie le modèle lié à ce ViewModel /// public TModel Model { get; protected set; } } }