1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
| using xxxxDTO;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace xxx.ViewModel.ViewModelWrapper
{
/// <summary>
/// Classe de base permettant de wrapper les classes du DTO afin que la modification des champ de ceux-ci provoque
/// une notification de type property change.
///
/// De plus, les vérifications de type métier sont appliquées par la classe dérivant de celle-ci.
/// </summary>
/// <typeparam name="T">Class de type DTO</typeparam>
public class WrapperViewModel<T> : DynamicObject
, INotifyPropertyChanged
, IDataErrorInfo where T : EntityBase
{
/// <summary>
/// Récupérer l'instance du modèle.
/// </summary>
public T Model { get; set; }
/// <summary>
/// Constructeur par défaut.
/// </summary>
public WrapperViewModel()
: base()
{
Model = null;
}
/// <summary>
/// Constructeur à utiliser.
///
/// Permet de wrapper une classe d'EntityBase.
/// </summary>
/// <param name="_value">Instance de classe dérivant d'EntityBase</param>
public WrapperViewModel(T _value)
{
Model = _value;
}
private bool TryGetMember(GetMemberBinder _binder, out object _objResult,object _objCible,bool _bLogError)
{
_objResult = null;
bool bRet = false;
string strPropertyName = _binder.Name;
PropertyInfo propertyInfo = _objCible.GetType().GetProperty(strPropertyName,BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (propertyInfo!=null && propertyInfo.CanRead)
{
_objResult = propertyInfo.GetValue(_objCible, null);
bRet = true;
}
else if (_bLogError)
{
String strError = String.Format("WrapperViewModel<{0}>.TryGetMember : impossible de trouver la propriété '{1}' !",typeof(T).Name,strPropertyName);
WPFExtToolkit.Logger.Log.Error(strError);
Debug.Assert(false, strError);
}
return bRet;
}
/// <summary>
/// Getter un membre.
///
/// Détecte au runtime la présence ou pas de ce membre puis récupère sa valeur.
/// </summary>
/// <param name="_binder">Paramètres du membre à récupérer</param>
/// <param name="_objResult">Résultat à mettre à jour</param>
/// <returns>true si le membre existe, false sinon.</returns>
public override bool TryGetMember(GetMemberBinder _binder, out object _objResult)
{
return TryGetMember(_binder, out _objResult,this,false)
|| TryGetMember(_binder, out _objResult,Model,true);
}
private bool TrySetMember(SetMemberBinder _binder, object _objValue,object _objCible,bool _bLogError)
{
bool bRet = false;
string strPropertyName = _binder.Name;
PropertyInfo property = _objCible.GetType().GetProperty(strPropertyName,BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (property!=null && property.CanWrite)
{
try
{
property.SetValue(_objCible, _objValue, null);
NotifyPropertyChanged(strPropertyName);
bRet = true;
}
catch(Exception _exception)
{
String strError = String.Format("WrapperViewModel<{0}>.TrySetMember : Exception lors du set de la propriété '{1}' :\n{2} !",typeof(T).Name,strPropertyName,_exception.Message);
WPFExtToolkit.Logger.Log.Error(strError);
Debug.Assert(false, strError);
}
}
else if (_bLogError)
{
String strError = String.Format("WrapperViewModel<{0}>.TrySetMember : impossible de trouver la propriété '{1}' !",typeof(T).Name,strPropertyName);
WPFExtToolkit.Logger.Log.Error(strError);
Debug.Assert(false, strError);
}
return bRet;
}
/// <summary>
/// Setter un membre.
///
/// Détecte au runtime la présence ou pas de ce membre puis set sa valeur.
/// </summary>
/// <param name="_binder">Paramètres du membre à setter</param>
/// <param name="_objValue">Valeur à setter pour ce membre</param>
/// <returns>true si le membre existe, false sinon.</returns>
public override bool TrySetMember(SetMemberBinder _binder, object _objValue)
{
return TrySetMember(_binder, _objValue,this,false)
|| TrySetMember(_binder, _objValue,Model,true);
}
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//
// Implémentyation INotifyPropertyChanged
//
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
#region INotifyPropertyChanged implementation
/// <summary>
/// Evénement property changed.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Lance l'évènement de changement de propriété.
/// </summary>
/// <param name="_strPropertyName">Nom de la propriété.</param>
public void NotifyPropertyChanged(string _strPropertyName)
{
if (PropertyChanged != null)
{
VerifyPropertyName(_strPropertyName);
PropertyChanged(this, new PropertyChangedEventArgs(_strPropertyName));
}
}
/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void VerifyPropertyName(String _strPropertyName)
{
// Vérifier que la propriété existe bien en tant que membre privé ou publique
PropertyInfo property = GetType().GetProperty(_strPropertyName,BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (property == null)
{
property = Model.GetType().GetProperty(_strPropertyName,BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}
if (property == null)
{
String strError = String.Format("WrapperViewModel<{0}>.NotifyPropertyChanged : Impossible de trouver la propriété '{1}'",typeof(T).Name,_strPropertyName);
WPFExtToolkit.Logger.Log.Error(strError);
Debug.Assert(false, strError);
}
}
#endregion
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//
// Gestion des Ereurs
//
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
#region Gestion des erreurs
/// <summary>
/// Non utilisé.
/// </summary>
string IDataErrorInfo.Error
{
get { throw new NotImplementedException(); }
}
/// <summary>
/// Test la colonne donné par son nom.
///
/// Vérifie en utilisant les annotations.
/// </summary>
/// <param name="_strColumnName">Nom de la colonne</param>
/// <returns>Une erreur si le champ n'est pas valide, null sinon.</returns>
public string this[string _strColumnName]
{
get
{
try
{ // Test en fonction des annotation de la classe wrappée
if (Model is IDataErrorInfo)
{
return ((IDataErrorInfo) Model)[_strColumnName];
}
Validator.ValidateProperty(Model.GetType().GetProperty(_strColumnName).GetValue(Model, null), new ValidationContext(Model, null, null)
{
MemberName = _strColumnName
});
}
catch(Exception ex)
{
return ex.Message;
}
return null; // Pas d'erreur
}
}
#endregion
}
} |
Partager