2012-05-07 16 views
7

Ich möchte mehrere Instanzen einer Klasse in meinem PropertyGrid anzeigen. Die Klasse sieht wie folgt aus:PropertyGrid readonly Eigenschaft auf Objektebene

public class Parameter 
{ 
    [Description("the name")] 
    public string Name { get; set; } 

    [Description("the value"), ReadOnly(true)] 
    public string Value { get; set; } 

    [Description("the description")] 
    public string Description { get; set; } 
} 

ich viele Instanzen dieser Klasse in einem TreeView haben. Wenn ich einen von ihnen in meinem TreeView auswähle, werden die Eigenschaften wie erwartet im PropertyGrid angezeigt. So weit so gut, aber ich möchte dieses Verhalten in der folgenden Weise anpassen:

Für jede einzelne Instanz möchte ich in der Lage sein zu verhindern, dass der Benutzer eine bestimmte Eigenschaft ändern kann. Durch Setzen von ReadOnly(true) innerhalb meiner Klasse (wie Sie im obigen Beispiel sehen können), werden alle Value Eigenschaften auf einer Klassenebene deaktiviert.

Nach einigen Recherchen fand ich die folgende Lösung, die mir die Möglichkeit gibt, eine bestimmte Eigenschaft zur Laufzeit aktivieren/deaktivieren:

PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["Value"]; 

ReadOnlyAttribute attr = 
     (ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)]; 

FieldInfo isReadOnly = attr.GetType().GetField(
     "isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance); 

isReadOnly.SetValue(attr, false); 

Dieser Ansatz funktioniert nur gut, aber leider auch auf Klassenebene nur. Das bedeutet, wenn ich die Value ‚s isReadOnly-false, Set alle meiner Parameter -Objekte haben die Value Eigenschaft beschreibbar. Aber ich will das NUR für dieses eine Objekt (also Objekt-Ebene). Ich möchte wirklich keine separaten Klassen für Lese-/Schreib- und Lese-Eigenschaften erstellen.

Als ich aus Ideen leite, wird Ihre Hilfe sehr geschätzt :)

Vielen Dank im Voraus!

EDIT: Ich brauche die Readonly-Eigenschaften ausgegraut, so dass der Benutzer sehen kann, dass es nicht erlaubt oder möglich ist, sie zu bearbeiten.

Antwort

4

EDIT: Verknüpfte Artikel entfernt wurde (ich hoffe nur vorübergehend). Sie können eine brauchbare Alternative in Antworten auf How to add property-level Attribute to the TypeDescriptor at runtime? kneifen. Grundsätzlich müssen Sie (zur Laufzeit) ReadOnlyAttribute über eine TypeDescriptor für diese Eigenschaft hinzufügen.


einen Blick auf diese alt Take aber schön article on CodeProject, es enthält viele nützliche Tools für die PropertyGrid.

Im Wesentlichen stellen Sie eine Klasse oder einen Delegaten bereit, der verwandt wird, um die Attribute Ihrer Eigenschaften abzurufen. Da es aufgerufen wird, indem die Instanz des Objekts übergeben wird, für das Sie Attribute abrufen möchten, können Sie das Objekt ReadOnlyAttribute mit einer Objektbasis zurückgeben (oder nicht).Kurz gesagt: Wenden Sie einen PropertyAttributesProviderAttribute auf Ihre Eigenschaft, schreiben Sie Ihren eigenen Anbieter und ersetzen Attribute aus der PropertyAttributes Sammlung basierend auf dem Objekt selbst (und nicht auf der Klasse)

+0

Ich habe das gesamte Dokument gelesen, verstehe aber Ihre Idee immer noch nicht. Könnten Sie mir ein kleines Codebeispiel geben, um es etwas übersichtlicher zu gestalten? Vielen Dank für Ihre Zeit :) –

+0

Siehe den Abschnitt * Dynamische Verwendung * in diesem Artikel. Kurz gesagt: Wenden Sie ein PropertyAttributesProviderAttribute auf Ihre Eigenschaft an, schreiben Sie Ihren eigenen Anbieter und ersetzen Sie die Attribute aus der PropertyAttributes-Auflistung basierend auf dem Objekt selbst (und nicht auf der Klasse). –

+0

Wie ich im Quellcode sehen kann, erfordert dies, die benutzerdefinierte PropertyGrid-Implementierung des Autors zu verwenden, damit es funktioniert? In meinem Fall muss ich ein vorhandenes PropertyGrid verwenden, das sich in einer DLL befindet (die ich nicht ändern kann). –

1

Sie können das Objekt mit einem benutzerdefinierten Typdeskriptor umschließen, aber ich denke, das wäre übertrieben, da Sie eine neue vom Typ descriptor abgeleitete Klasse erstellen müssen.

Also, eine einfachste Lösung wäre, eine Flagge zu haben, so etwas wie:

public class Parameter 
{ 
    private string thevalue; 

    [Browsable(false)] 
    public bool CanEditValue { get; set; } 

    [Description("the name")] 
    public string Name { get; set; } 

    [Description("the description")] 
    public string Description { get; set; } 

    [Description("the value"), ReadOnly(true)] 
    public string Value { 
     get { return this.thevalue; } 
     set { if (this.CanEditValue) this.thevalue = value; } 
    } 
} 
+0

Hallo Jaime, wäre Ihr Vorschlag mit Doubling-Eigenschaften akzeptabel, weil es wirklich ist einfach. Ich probierte dies und leider deaktiviert die Überprüfung innerhalb des Setter nicht Eigenschaft bearbeiten wie ReadOnly (true) ... so ist es nicht ausgegraut. Benutzer werden denken, dass es änderbar ist, aber ihre Eingabe wird einfach verworfen. irgendwelche anderen weniger komplexen Ideen? :) –

+0

Ich fürchte, dass Sie eine eindeutige Option ist, einen Eigenschaftsdeskriptor abzuleiten und die bedingte IsReadOnly-Eigenschaft Getter zu implementieren. –

Verwandte Themen