The Artima Developer Community
Sponsored Link

.NET Buzz Forum
PropertyGrid löst Event PropertyValueChanged bei Collections nicht aus

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
-

Posts: 1524
Nickname: nitronic
Registered: Jul, 2006

Norbert Eder works as a software architect.
PropertyGrid löst Event PropertyValueChanged bei Collections nicht aus Posted: Feb 7, 2008 2:49 AM
Reply to this message Reply

This post originated from an RSS feed registered with .NET Buzz by -.
Original Post: PropertyGrid löst Event PropertyValueChanged bei Collections nicht aus
Feed Title: Norbert Eder - Living .NET
Feed URL: http://feeds.feedburner.com/NorbertEder-Livingnet
Feed Description: Copyright (c)2005, 2006 by Norbert Eder
Latest .NET Buzz Posts
Latest .NET Buzz Posts by -
Latest Posts From Norbert Eder - Living .NET

Advertisement
Das PropertyGrid besitzt ein Event namens PropertyValueChanged. Dieses wird ausgelöst, wenn eine Eigenschaft editiert wird. Dies funktioniert soweit auch gut, außer die Eigenschaft wird durch eine Collection dargestellt. In diesem Falle wird nichts ausgelöst.

Hintergrund


Das Problem liegt darin, dass sich die Collection selbst nicht ändert, wenn sich in einem der Werte eines Child-Objektes ein Wert ändert. Ebenfalls ändert sich die Collection nach außen hin nicht, wenn neue Elemente hinzugefügt werden. Sehen wir uns die Implementierung auf Seiten des PropertyGrids an.
Das PropertyGrid besitzt eine Auflistung GridEntryCollection. Diese beinhält GridEntry-Objekte, welche die einzelnen Properties darstellen. GridEntry besitzt nun eine Methode EditPropertyValue. Diese überprüft, ob sich der Wert verändert hat und setzt darauf hin ein Commit ab, oder nicht (wenn keine Änderung). Im Commit wird anschließend der besagte Event ausgelöst. Hier nun der relevante Teil aus der Methode:
object propertyValue = this.PropertyValue;
object obj3 = this.UITypeEditor.EditValue
    (this, this, propertyValue);
if (!this.Disposed)
{
    if ((obj3 != propertyValue) 
        && this.IsValueEditable)
    {
        iva.CommitValue(this, obj3);
    }
    if (this.InternalExpanded)
    {
        PropertyGridView.GridPositionData data = 
          this.GridEntryHost.CaptureGridPositionData();
        this.InternalExpanded = false;
        this.RecreateChildren();
        data.Restore(this.GridEntryHost);
    }
    else
    {
        this.RecreateChildren();
    }
}

Hier ist nun schön zu erkennen, dass lediglich die Objekte miteinander verglichen werden, was bei einer Collection natürlich grundsätzlich keine Änderung entdecken lässt. Dadurch muss man sich mit einem Workaround behelfen.

Mögliche Workarounds


Der erste Workaround ist vermutlich der, der mit dem geringsten Aufwand verbunden ist: Es gibt einige 3rd Party Produkte, welche diesen „Fehler“ erkannt und ausgemerzt haben. Damit muss selbst keine Implementierung vorgenommen werden, jedoch sind die meisten dieser Produkte kommerzieller Natur und kosten somit einige Euros.
Eine weitere Möglichkeit ist, selbst Hand anzulegen und in die Tasten zu klopfen. Dazu muss man sich nun einen grundsätzlichen Gedanken machen. Wie kann erreicht werden, dass der Objekt-Vergleich in oben gezeigter Methode erkennt, dass das Objekt geändert wurde? Korrekt, wir müssen die Collection klonen. Das heißt, die Objekte der Collection und auch die Collection selbst müssen das Interface ICloneable implementieren.
Die Collections selbst werden im PropertyGrid in einem CollectionEditor angezeigt. Dieser ist standardmäßig für alle Collections der gleiche. Diesen müssen wir nun für unsere Collection-Eigenschaft austauschen, indem wir eine eigene Klasse erstellen, die von UITypeEditor ableitet:
public class CustomCollectionEditor : UITypeEditor
{
    private CollectionEditor _editor = 
      new CollectionEditor(typeof(CustomCollection));
    
    public override object EditValue(
      ITypeDescriptorContext context, 
      IServiceProvider provider, 
      object value)
    {
        if (value != null)
        {
            value = this._editor.EditValue(context, provider, value);
            CustomCollection list = (CustomCollection)value;
            return list.Clone();
        }

        return base.EditValue(context, provider, value);
    }

    public override UITypeEditorEditStyle GetEditStyle(
      ITypeDescriptorContext context)
    {
        return this._editor.GetEditStyle(context);
    } 
}

Im Grunde passiert hier wenig Spannendes. Es wird lediglich bei einem Edit die Collection geklont und die neue Collection zurück geliefert. Dadurch erkennt nun das PropertyGrid eine Änderung und aktiviert ihrerseits das Event PropertyValueChanged. Daraufhin ist es nun möglich festzustellen, dass a) in der Collection eine Änderung passiert sein muss und b) können wir feststellen wo diese passiert ist.
Schlussendlich muss nun noch der jeweiligen Eigenschaft zugewiesen werden, dass diese mit dem eigenen CustomCollectionEditor zu öffnen ist. Dazu sind folgende Attribute bei der entsprechenden Property zu setzen:
private CustomCollection _collection = new CustomCollection();

[TypeConverter(typeof(CustomCollection))]
[Editor(typeof(CustomCollectionEditor), typeof(UITypeEditor))]
public CustomCollection MyCollection
{
  get { return this._collection; }
  set { this._collection = value; }
}

Hierzu gibt es noch einen kleinen Tipp: Es ist darauf zu achten, dass auch der Setter tatsächlich vorhanden ist. Im GridEntry wird abgefragt, ob das Object editierbar ist (IsValueEditable). Wäre nur ein Getter vorhanden, wäre IsValueEditable auf false und der Wert würde nicht committed warden, wodurch auch das Event PropertyValueChanged nicht ausgelöst werden würde.

Fazit


Schön wäre es natürlich, würde das PropertyGrid diese Funktionalität anbieten. Da das nicht der Fall ist, muss man selbst etwas nachhelfen. Die oben gezeigte Variante kommt dem gewünschten schon recht nahe, auch wenn der besprochene Event erst angetriggert wird, nachdem der CollectionEditor geschlossen wird. Zwar in manchen Fällen (Eingabevalidierung) nicht erwünscht, lässt sich aber so einfach nicht beheben. Dennoch bietet diese Variante eine einfache und gute Möglichkeit, das gewünschte Ziel zu erreichen.

Read: PropertyGrid löst Event PropertyValueChanged bei Collections nicht aus

Topic: Jänner 2008 im Rückblick Previous Topic   Next Topic Topic: MOSS 2007 - Geographically Dispersed Sites

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use