Laden...

PropertyDescriptor.AddValueChanged will nicht

Erstellt von JunkyXL vor 12 Jahren Letzter Beitrag vor 12 Jahren 5.448 Views
JunkyXL Themenstarter:in
1.665 Beiträge seit 2006
vor 12 Jahren
PropertyDescriptor.AddValueChanged will nicht

Hallo,

ich bin am Verzweifeln. Ich hab das schon 1000 mal gemacht, und heute Nacht ging das auch noch.
Jetzt nicht mehr. Und zwar folgendes:

Der Bequemlichkeit halber will ich Property-Änderungen dynamisch überwachen:

foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(this))
{
    pd.AddValueChanged(this, this.OnPropertyValueChanged);
}
// ...
private void OnPropertyValueChanged(object sender, EventArgs e)
{
}

An sich nichts spektakuläres. Der übergebene Handler in AddValueChanged wird nie aufgerufen, wenn sich ein Property-Wert ändert. Vielleicht seh ich gerade auch den Wald vor lauter Bäumen nicht. Aber ich kann keinen Fehler entdecken.

Hier die vollständige Test-Klasse, mit der es (bei mir) nicht funktioniert:

public class Class1
{
    public void Test()
    {
        this.Value = 0;

        foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(this))
        {
            pd.AddValueChanged(this, this.OnPropertyValueChanged);
        }

        // Wertänderungsbenachrichtigung erzwingen
        this.Value = 4711;
        this.Value = 0815;
    }

    private void OnPropertyValueChanged(object sender, EventArgs e)
    {
        // Wird nie aufgerufen
        Debug.Assert(false, "this.Value changed: " + this.Value);
    }

    public int Value { get; set; }
}
var test = new Class1();
test.Test();

Im Internet finde ich keine nützliche Informationen. Und da es so schon immer funktioniert hat, wollte ich auch nicht auf das "neue" DependencyProperty Handling umsteigen.

Das einzige was ich gefunden habe, ist das SupportChangeEvents Property auf dem PropertyDescriptor was auf false steht, was mit der Nicht-Benachrichtigung zu tun haben könnte. Aber damit kann ich auch nicht viel anfangen, da ich auch Basistypen wie int und string verwende. Ich musste mich auch nie darum kümmern.

Das Ganze habe ich in einer VM (Windows XP SP 3) mit Visual C# Express 2010 am Laufen. Ich kann mir nicht vorstellen, dass die Express Version solche Einschränkungen hat?!

5.742 Beiträge seit 2007
vor 12 Jahren

Hallo JunkyXL,

ich denke mal, du musst noch entweder INotifyPropertyChanged implementieren oder ein [Value]Changed-Event (EDIT: "Value" ist hierbei der Propertyname!) bereitstellen - ansonsten kann der PropertyDescriptor ja gar nicht wissen, wenn sich die Property ändert.

6.862 Beiträge seit 2003
vor 12 Jahren

Hallo,

erstmal bezüglich VS Express: Hat damit absolut gar nichts zu tun, da das ja nen Thema der Runtime und nicht der IDE ist.

Du hast zwei Möglichkeiten: So wie winSharp93 es vorgeschlagen hat - steht so übrigens auch in der Doku zu dem von dir genannten SupportChangeEvents Property 😃

Oder wenn du die nicht implementieren willst, musst du Wertänderungen immer über PropertyDescriptor.SetValue vornehmen.

Baka wa shinanakya naoranai.

Mein XING Profil.

JunkyXL Themenstarter:in
1.665 Beiträge seit 2006
vor 12 Jahren

bezüglich VS Express: Hat damit absolut gar nichts zu tun, da das ja nen Thema der Runtime und nicht der IDE ist.

Ich weiß 😃 Das sind aber diese Momente wo ich anfange, alles in Erwägung zu ziehen 😃

Das mit dem Interface habe ich schon drin gehabt, hab das im Post nur ausgelassen.
Habe jetzt nochmal ein neues Sample gemacht. Sowohl Interface implementiert, als auch EventHandler ValueChanged zusätzlich bereitgestellt:

class Program
{
    static void Main(string[] args)
    {
        var i = new MyClass();
        i.ValueChanged += new EventHandler(i_ValueChanged);
        i.PropertyChanged += new PropertyChangedEventHandler(i_PropertyChanged);
        i.Property = "test";

        Console.ReadLine();
    }

    static void i_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Console.WriteLine("Property value changed");
    }

    static void i_ValueChanged(object sender, EventArgs e)
    {
        Console.WriteLine("Property value changed");
    }
}

public class MyClass : INotifyPropertyChanged
{
    public MyClass()
    {
        foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(this))
        {
            pd.AddValueChanged(this, this.OnValueChanged);
        }
    }

    private void OnValueChanged(object sender, EventArgs e)
    {
        if (this.ValueChanged != null)
        {
            this.ValueChanged(this, new PropertyChangedEventArgs(""));
        }

        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(""));
        }
    }

    public event EventHandler ValueChanged;

    #region INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    public string Property { get; set; }
}
5.742 Beiträge seit 2007
vor 12 Jahren

Aber auslösen tust du das Event ja nie?!?

Du musst in den Setter den entsprechenden Code schreiben - sollte aber genügend Beispiele dazu geben.

6.862 Beiträge seit 2003
vor 12 Jahren

Hallo,

geschickter wäre es vielleicht auch gewesen nicht ValueChanged zu schreiben, sondern <Value>Changed. Das Value ist nur nen Platzhalter, das Changed Event muss so heißen wie das Property.

Baka wa shinanakya naoranai.

Mein XING Profil.

5.742 Beiträge seit 2007
vor 12 Jahren

geschickter wäre es vielleicht auch gewesen nicht ValueChanged zu schreiben, sondern <Value>Changed

Ja, da hast du recht, ich hab's mal geändert.

JunkyXL Themenstarter:in
1.665 Beiträge seit 2006
vor 12 Jahren

Aber auslösen tust du das Event ja nie?!?

Du musst in den Setter den entsprechenden Code schreiben - sollte aber genügend Beispiele dazu geben.

Das Event will ich ja auch gar nicht selber auslösen. Das soll ja eben automatisch über den PropertyDescriptor mit AddValueChanged geschehen.

Verstehe ich eure Hinweise also richtig, für jedes Property ein -Changed Event bereitzustellen? Wo ist denn da noch der Mehrwert von AddValueChanged?
Ich bin mir auch mittlerweile nicht mehr sicher, ob wir noch von dem selben Problem sprechen..

Ich hab das bisher immer so gemacht, den PropertyDescriptor jedes Property's einer Klasse zu durchlaufen und in AddValueChanged eine stupide Methode zu hinterlegen, die aufgerufen wird, sobald sich irgendein Property-Wert ändert, was aber nicht passiert.

Aber soweit erstmal Danke für eure Antworten.

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo JunkyXL,

Ich hab das schon 1000 mal gemacht, und heute Nacht ging das auch noch.

schwer zu glauben. Jedenfalls nicht bei Klassen, die die nötigen Events nicht besitzen.

Ich hab das bisher immer so gemacht, den PropertyDescriptor jedes Property's einer Klasse zu durchlaufen und in AddValueChanged eine stupide Methode zu hinterlegen, die aufgerufen wird, sobald sich irgendein Property-Wert ändert, was aber nicht passiert.

Aber nur bei Klassen, die die nötigen Events bereitstellen und auslösen.

Verstehe ich eure Hinweise also richtig, für jedes Property ein -Changed Event bereitzustellen?

Bereitstellen und auslösen, ja. Oder eben INotifyPropertyChanged implementieren (also auch hier wieder bereitstellen und auslösen).

Es gibt ja eine Menge, was in C# automatisch geht, aber per Voodoo gehen die Sachen nun auch wieder nicht.

Wo ist denn da noch der Mehrwert von AddValueChanged?

Darin, dass man per Reflection den EventHandler registrieren kann. Es hat keiner behauptet, dass das Registrieren des EventHandler das Bereitstellen und Auslösen der Events ersetzt - außer bei der Verwendung von PropertyDescriptor.SetValue.

herbivore

5.742 Beiträge seit 2007
vor 12 Jahren

Evtl. ist auch [Artikel] Attribute zur Prüfung von Properties verwenden einen Blick wert - damit könntest du das Event sozusagen via Attribut auslösen.

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo JunkyXL,

im Startbeitrag des Artikels wird das Event allerdings nicht durch das Attribut ausgelöst, sondern durch einen expliziten Aufruf einer (universellen) Check-Methode, die das Attribut nur heranzieht, um die konkrete Prüfung durchzuführen. Weiter unten im Thread wird jedoch noch eine Variante mit AOP/PostSharp beschrieben, bei der dann tatsächlich alles über Attribute läuft und im Quellcode kein expliziter Aufruf erfolgen muss, sondern von PostSharp während des Builds in die Assembly injiziert wird.

herbivore

JunkyXL Themenstarter:in
1.665 Beiträge seit 2006
vor 12 Jahren

Danke für eure Antworten.

Ich habe jetzt den Grund für meine Verwirrung gefunden.
Ich habe AddValueChanged in einigen Projekten benutzt, um ein Objekt zu überwachen, über das ich selbst nicht die Kontrolle habe. Und anscheinend werden die Properties auf dem Objekt mit SetValue gesetzt. Das war mir nicht bewusst.