SOLVED - Übersetzungshilfe



  • Hallo.

    Ich habe einen Code gefunden, mit dem ich die Sichtbarkeit einer Eigenschaft in einem PropertyGrid-Steuerelement abhängig von einer anderen Eigenschaft dieser Klasse steuern kann.

    Glaubt mir, ich wühle mich jetzt seit zwei Stunden durch die Klassen PropertyDescriptor, PropertyDescriptorCollection, Attribute und ICustomTypeDescriptor aber ich verstehe einfach nicht, wie das funktioniert. Klassen und deren Vererbung hab ich eigentlich schon begriffen.
    Ich verstehe nicht, wo hier das Attribut "BrowseAble", welches die Sichtbarkeit einer Eigenschaft bestimmt, geändert wird.

    Vielleicht könnt ihr mir da helfen, denn ich will:
    a, keinen Code in meinem Programm, den ich nicht verstehe und
    b, den Code etwas umschreiben, so dass ich die Sichtbarkeit von Eigenschaften auch von Eigenschaften anderer Klassen abhängig machen kann.

    Problematisch ist auch, dass der Code nur funktioniert, wenn die Eigenschaft mit dem jeweiligen Wert initialisiert wird. Wenn ich den Wert der Eigenschaft im PropertyGrid ändere, wird die Prüfung gar nicht mehr ausgeführt.

    Der Code:

    #region DynamicDisplay
        [AttributeUsage(AttributeTargets.Property, Inherited = true)]
        class DynamicPropertyFilterAttribute : Attribute
        {
            string _propertyName;
            public string PropertyName
            {
                get { return _propertyName; }
            }
    
            string _showOn;
            public string ShowOn
            {
                get { return _showOn; }
            }
    
            public DynamicPropertyFilterAttribute(string propName, string value)
            {
                _propertyName = propName;
                _showOn = value;
            }
        }
    
        public class FilterablePropertyBase : ICustomTypeDescriptor
        {
    
            protected PropertyDescriptorCollection GetFilteredProperties(Attribute[] attributes)
            {
                PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(this, attributes, true);
                PropertyDescriptorCollection finalProps = new PropertyDescriptorCollection(new PropertyDescriptor[0]);
    
                foreach (PropertyDescriptor pd in pdc)
                {
                    System.Diagnostics.Trace.WriteLine("pd = " + pd.Name);
                    bool include = false;
                    bool Dynamic = false;
                    foreach (Attribute a in pd.Attributes)
                    {
                        System.Diagnostics.Trace.WriteLine("a = " + a.ToString());
                        //if (a is CSF2D_21050104.DynamicPropertyFilterAttribute)
                        if (a is DynamicPropertyFilterAttribute)
                        {
                            Dynamic = true;
    
                            DynamicPropertyFilterAttribute dpf = (DynamicPropertyFilterAttribute)a;
                            PropertyDescriptor temp = pdc[dpf.PropertyName];
                            if (dpf.ShowOn.IndexOf(temp.GetValue(this).ToString()) > -1)
                            {
                                include = true;
                            }
                        }
                    }
                    if (!Dynamic || include)
                        finalProps.Add(pd);
                }
    
                System.Diagnostics.Trace.WriteLine("Propcount=" + finalProps.Count.ToString());
                return finalProps;
            }
    
            #region ICustomTypeDescriptor Members
    
            public TypeConverter GetConverter()
            {
                return TypeDescriptor.GetConverter(this, true);
            }
    
            public EventDescriptorCollection GetEvents(Attribute[] attributes)
            {
                return TypeDescriptor.GetEvents(this, attributes, true);
            }
    
            EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
            {
                return TypeDescriptor.GetEvents(this, true);
            }
    
            public string GetComponentName()
            {
                return TypeDescriptor.GetComponentName(this, true);
            }
    
            public object GetPropertyOwner(PropertyDescriptor pd)
            {
                return this;
            }
    
            public AttributeCollection GetAttributes()
            {
                return TypeDescriptor.GetAttributes(this, true);
            }
    
            public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                return GetFilteredProperties(attributes);
            }
    
            PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties()
            {
                return GetFilteredProperties(new Attribute[0]);
            }
    
            public object GetEditor(Type editorBaseType)
            {
                return TypeDescriptor.GetEditor(this, editorBaseType, true);
            }
    
            public PropertyDescriptor GetDefaultProperty()
            {
                return TypeDescriptor.GetDefaultProperty(this, true);
            }
    
            public EventDescriptor GetDefaultEvent()
            {
                return TypeDescriptor.GetDefaultEvent(this, true);
            }
    
            public string GetClassName()
            {
                return TypeDescriptor.GetClassName(this, true);
            }
    
            #endregion
        }
        #endregion
    

    Will man den Filter jetzt nutzen, leitet man eine Klasse von DynamicPropertyFilterAttribute ab und definiert dort für die Eigenschaft, deren Sichtbarkeit dynamisch verwaltet werden soll einfach das Attribut:

    [DynamicPropertyFilter("Property", "Wert bei dem die Eigenschaft angezeigt werden soll")]
    

    Das Ganze hat dann folgenden Effekt:
    http://dzaebel.net/PropertyGridDynamic.htm

    Vielen Dank schon mal,
    CJens



  • Hallo,

    das PropertyGrid ruft für das gebundene Objekt "GetProperties" auf. Deine Nutzeredfinierte Klasse "FilterablePropertyBase" ruft dann intern "GetFilteredProperties" auf.

    Normalerweise liefert "GetProperties" immer alle Properties des Objektes. Die Klasse wiederum prüft aber ob die Properties jeweils das Attribut besitzen und leitet aus dem Attribut ab ob die Property zurück zu liefern ist. Kann man machen... ist aber .... sagen wir so, etwas merkwürdig.

    Warum sollen Properties vor dem Benutzer verschleiert werden? Was genau hast du vor?

    Das beschriebene funktioniert übrigens nur für das PropertyGrid und andere Controls die auf diese Weise ermitteln welche Properties es gibt. Nutzer die Zugriff auf den Code haben, kommen dennoch weiterhin an alle Properties.

    Wenn es dir nur darum geht, die Properties nicht im PropertyGrid anzuzeigen, solltest du eventuell noch mal einen Wrapper drüber legen.

    Im allgemeinen sollte man auch vorsichtig sein mit Reflection, da dies die OOP aushebelt.



  • Danke, damit hast Du mir wirklich geholfen. Langsam verstehe ich das, zusammen mit ein paar weiteren Recherchen.

    Warum sollen Eigenschaften verschleiert werden? Stell Dir vor ich habe eine Klasse "Fahrzeug" mit der Enumeration, welche die Eingabe "Motorrad" und "Auto" zulässt. Dazu gibt es noch vier double Variablen für den Reifendruck für jeden Reifen. Wählt der Benutzer jetzt bei Typ "Motorrad" aus, sollen interaktiv nur die beiden ersten Werte für Reifendruck angezeigt werden, da das Motorrad ja nur zwei Räder hat. Wählt er dann Auto, sollen alle vier Typen angezeigt werden.

    Eigentlich ist es das, was mit mit Vererbungen regelt - aber hier soll das ja interaktiv im Propertygrid funktionieren und es funktioniert wunderbar.



  • Der Ansatz ist irgendwie nicht der richtige. - Warum muss dein Fahrzeug wissen, dass es ein Auto ist?!

    Richtiger wäre es, das Objekt im PropertyGrid entsprechend auszutauschen. Die Auswahl, welches zu verwenden ist findet dann natürlich nicht im PropertyGrid statt.

    public abstract class Fahrzeug
    {
       public abstract string Name { get; set; }
       // ..
    }
    
    public class Car : Fahrzeug
    {
       public override string Name { get; set; }
       // ...
    }
    
    // ...
    void selectedType_Changed(Object sender, Eventargs e)
    {
        switch(type)
        {
             case typeof(Car): 
                  this.propertyGrid.SelectedObject = new Car();
                  break;
             // ..
        }
    }
    

    Vorallem möchte ich das Fahrzeug mal sehen, das von jetzt auf gleich vom Auto zum Motorad wird. 😋



  • Das ist sehr schwierig, denn das ganze ist strukturell sehr verwoben. Sicher hat jede Methode seine Vor- und Nachteile. Aber da ich nicht so viele von diesen Klassen erstelle ist es auch nicht weiter schlimm, ein paar ungenutzte Variablen mitzuschleppen.

    Auf jeden Fall funktioniert es 🙂


Log in to reply