Cette question prendra probablement un certain temps pour expliquer, et je dois fournir ... fondObtenez l'instance d'objet qui contient une propriété spécifiée
Ceci est juste quelque chose que je joue avec et sur les ISN » t pour la production, mais au moment où j'ai un code qui ressemble à ceci:
var myDataModel = new DataModel();
myDataModel.PropertyChanged += myDataModel_PropertyChanged;
myDataModel.ChangeProperty(t => t.TestValue, 2);
Ainsi, plutôt que d'utiliser myDataModel.TestValue = 2
directement, j'utilise une méthode d'extension ChangeProperty
pour que je puisse gérer tous les événements de changement et fais tout ce que je veux dans un endroit. Ma méthode d'extension ressemble à ceci (et oui, je sais qu'il est hacky):
public static class NotifyPropertyChangedExtensions
{
public static void ChangeProperty<T, U>(
this T instance,
Expression<Func<T, U>> propertyToChange,
U newValue)
{
var member = propertyToChange.Body as MemberExpression;
if (member != null)
{
if (!propertyToChange.Compile().Invoke(instance).Equals(newValue))
{
var setProperty = instance.GetType().GetProperty(
member.Member.Name,
BindingFlags.SetProperty |
BindingFlags.Public |
BindingFlags.Instance);
if (setProperty != null)
{
// actually set the property
setProperty.SetValue(instance, newValue, null);
// raise the property changed event
if (typeof(INotifyPropertyChanged).IsAssignableFrom(
typeof(T)))
{
var delegatesToCall =
instance.GetType().GetField("PropertyChanged",
BindingFlags.Instance |
BindingFlags.NonPublic)
.GetValue(instance) as MulticastDelegate;
if (delegatesToCall != null)
{
var eventArgs = new PropertyChangedEventArgs(
setProperty.Name);
foreach (var @delegate in
delegatesToCall.GetInvocationList())
{
@delegate.Method.Invoke(
@delegate.Target,
new object[] { instance, eventArgs });
}
}
}
}
}
}
else
{
throw new ArgumentException(
string.Format(
"Cannot determine the property to change {0}",
propertyToChange));
}
}
}
Avec cette architecture, mon modèle de données est assez propre:
public class DataModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int TestValue { get; set; }
}
C'est, je peux utiliser les propriétés d'auto- et ne pas besoin de se soucier des événements de collecte etc.
maintenant, ce que je veux vraiment faire quelque chose plus proche de celle-ci:
var dataModel = new DataModel();
myDataModel.PropertyChanged += myDataModel_PropertyChanged;
myDataModel.TestValue.Set(2); // this is what I want...
Donc, je pense que je vais avoir besoin d'une méthode d'extension - mais je ne vois que comment envoyer la propriété elle-même (le TestValue dans ce cas), et la nouvelle valeur. Alors, je me suis demandé s'il était possible, avec une propriété, de trouver l'instance de la classe à laquelle il appartenait?
Tbh Je ne ferais pas cela. Vous imputez la responsabilité de déclencher correctement l'événement PropertyChanged de la classe à son utilisateur. Cela casse le principe d'encapsulation. La classe doit s'assurer qu'elle se comporte comme prévu, pas le code qui l'utilise. – dtb
@dtb: Ceci est une question "est-ce possible", je ne mettrais pas ce code de production proche ... –
Au lieu de 'var setProperty = instance.GetType(). GetProperty (...)', qui repose sur la propriété * name *, vous devriez probablement obtenir la propriété de propertyToChange. Par exemple, dans votre code, '(PropertyInfo) member.Member' le ferait. – Timwi