| 

.NET C# Java Javascript Exception

5
Hallo,

das PropertyGrid stellt mir für ein Property vom Typ IList<IObject>
ein leeres Feld dar.

Wenn das Property hingegen den Typ List<IObject>
hat kann ich schön einen Dialog mit der Auflistung der Listenelemente
öffnen.
Kann mir bitte jemand helfen? Hab auch schon in anderen Foren gesucht, jedoch
keine funktionierende Lösung gefunden.

Nach hinzufügen des Attributes [TypeConverter(typeof(CollectionConverter))]
zeigt das PropertyGrid zwar "(Auflistung)", jedoch fehlt immer noch der Button
zu öffnen des Dialogs.
Ich möchte nur die in der Liste enthaltenen Elemente sehen. Nix hinzufügen,
entfernen oder ändern.

Beispiel:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace PropertyGridTest
{
//######################################################
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

Familiy family = new Familiy();
family.Members.Add(new Person() {Name="Mum"});
family.Members.Add(new Person() {Name="Dad"});
family.Members.Add(new Person() {Name="I"});

propertyGrid1.SelectedObject = family;
}
}

//######################################################
interface IPerson
{
string Name
{
get;
set;
}
}

//######################################################
interface IFamiliy
{
IList<IPerson> Members
{
get;
}
}

//######################################################
class Person : IPerson
{
#region IPerson Members

public string Name
{
get; set;
}

#endregion
}

//######################################################
class Familiy : IFamiliy
{
private List<IPerson> mMembers = new List<IPerson>();

#region IFamiliy Members

[TypeConverter(typeof(CollectionConverter))]
public IList<IPerson> Members
{
get { return mMembers; }
}

#endregion
}


}


Vielen Dank vorab.
News:
01.06.2012
Schnulle500 43 1 4
2 Antworten
3
Nach allem, was ich ergoogeln konnte, ist der CollectionConverter für die nicht-generische Version von IList gedacht. Darauf wirst Du vermutlich nicht umstellen wollen, und selbst wenn, würdest Du die Persons nicht so sehen, wie vermutlich gewünscht. Ich hab's mal ausprobiert - sieht sehr nach Aufruf der ToString()-Methode aus.

Was hingegen funktioniert: sag dem PropertyGrid, welchen Editor es hier verwenden soll (Du mußt dazu System.Design.dll einbinden und dafür mit der "Voll-Version", nicht mit dem Client Profile arbeiten):

[EditorAttribute(typeof(System.ComponentModel.Design.CollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
public IList<IPerson> Members
{
get { return mMembers; }
}

Damit siehst Du die einzelnen Einträge in der Liste und kannst sie sogar editieren. Was hingegen nicht funktioniert, ist das Hinzufügen neuer Elemente - was aber für Dich ausreichend wäre, wie Du schreibst.

Exkurs: Rein technisch liegt das vermutlich daran, dass IList<T> keine Add-Methode hat - die braucht der CollectionEditor aber, wie dieser sehr lesenswerte Artikel auf CodeProject erklärt. Aber selbst wenn es sie gäbe: der Editor wüßte dann immer noch nicht, welche konkrete Implementierung von IPerson er denn bitteschön instanziieren soll. Falls Du diese Funktionalität irgendwann doch brauchen solltest, wirst Du kaum um eine eigene Editor-Implementierung herumkommen. Alternativ könntest Du dann mit den konkreten Klassen statt der Interfaces arbeiten, oder zumindest eine Wrapper-Klasse schreiben, die nur für das PropertyGrid hergenommen wird und die relevanten Propertys über die konkreten Typen bereitstellt.

Ansonsten: Willkommen bei codekicker! Bitte vergiss nicht, mir und anderen Lesern per Kommentar oder Bewertung und ggf. Klick auf das grüne Akzeptieren-Häkchen zu signalisieren, ob die Frage damit beantwortet ist. Danke!
03.06.2012
Matthias Hlawatsch 13,2k 4 9
+1 für die Arbeit, das alles zu googlen und so aufzubereiten.
ffordermaier 04.06.2012
Vielen Dank,
das funktioniert super, so.
Schnulle500 06.06.2012
2
Mit einem eigenen TypeDescriptor (CustomTypeDescriptor) für Family kannst Du durch Überschreiben der GetProperties()-Methode für die Property Members einfach einen anderen PropertyDescriptor zurückgeben, der die Members-Property mit einer anderen Listenimplementierung zur Verfügung stellt. Da es - wie Du schreibst - mit List<T> funktioniert, dürfte es also ausreichen, einfach List<T> zu verwenden. Bearbeiten der Liste funktioniert entweder durch einen eigenen Editor oder durch Verwendung einer geeigneten Listenimplementierung (inkl. konkretem Typ) via TypeDescriptor, sodass der Standardeditor ausreicht.

Als ich vor einigen Jahren viel mit WinForms Controls und Designern gearbeitet habe, habe ich zuletzt nur noch mit TypeDescriptoren und ControlDesignern gearbeitet. Da hatte ich alle Möglichkeiten und es hat auch zuverlässig funktioniert.

Update (M.H.):
Ich habe das mal versucht nachzubauen, hier der Code zur Illustration von Florians Vorschlag:
[TypeDescriptionProvider(typeof(FamilyTypeDescriptionProvider))]
class Familiy : IFamiliy
{ //wie gehabt, keine Attribute für die Members-Property notwendig
}

class FamilyTypeDescriptionProvider : TypeDescriptionProvider
{
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new FamiliyDescriptor();
}
}

class FamiliyDescriptor : CustomTypeDescriptor
{
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
var baseProps = base.GetProperties(attributes);

var props = new PropertyDescriptorCollection(
new PropertyDescriptor[] { new MembersDescriptor () }
);

return props;
}
}

class MembersDescriptor : PropertyDescriptor
{
public MembersDescriptor ()
: base("Members4Grid", new Attribute[] { })
{
}

public override object GetValue(object component)
{
return ((Familiy)component).Members;
}

public override Type PropertyType
{
get { return typeof(List<IPerson>); }
}

public override bool CanResetValue(object component)
{
return false;
}

public override Type ComponentType
{
get { throw new NotImplementedException(); }
}

public override bool IsReadOnly
{
get { return true; }
}

public override void ResetValue(object component)
{
throw new NotImplementedException();
}

public override void SetValue(object component, object value)
{
throw new NotImplementedException();
}

public override bool ShouldSerializeValue(object component)
{
return false;
}
}
04.06.2012
ffordermaier 8,4k 3 9
1
+1 für den Hinweis auf die Möglichkeiten, die TypeDescriptoren bieten und die ich immer wieder übersehe. Vielleicht auch, weil's halt arg viel boiler-plate code ist. Habe mal versucht, eine lauffähige Lösung zu Deinem Vorschlag zusammenzubauen, siehe das Edit der Antwort. Pro: läuft vermutlich auch mit dem Client Profile und ist wohl auch besser ausbaufähig. Con: viel mehr Code, und man muß noch extra Klimmzüge machen, um die Hinzufügen/Entfernen-Buttons zu disablen, die hier nicht gewünscht sind (aber funktionieren würden, wenn man in PropertyType ganz frech typeof(List<Person>) schriebe).
Matthias Hlawatsch 04.06.2012
Vielen lieben Dank für die Ausarbeitung meines doch sehr knapp formulierten Vorschlags, Matthias.
Ich geb Dir Recht, wenn ich "nur" ein bisschen am DesignTime-Feeling eines Controls schrauben möchte, sind TypeDescriptoren (und auch ControlDesigner) schon verhältnismäßig viel Code, um ans Ziel zu kommen.
Wenn man aber umfangreiche DesignTime-Unterstützung bieten will, merkt man früher oder später, dass man mit den beiden angesprochenen Typen tatsächlich alles an DesignTime hinbekommt, was man möchte - und sogar noch etwas mehr (wenn man, wie Du schon schreibst, etwas frecher wird ;-).
ffordermaier 05.06.2012
1
Boah,
ist zwar ein wenig Aufwand, aber eine komplette Lösung.
Vielen Dank für die mühevolle Aufarbeitung.
Das ist mal eine perfekte Hilfe.
Schnulle500 06.06.2012
1
Gemeinsam sind wir stark ;-)
Mich (bestimmt auch alle anderen Aktiven) freut es, dass Du als neues Mitglied in der Community hier schnell eine "perfekte Hilfe" erhalten hast. Zögere bitte nicht, weitere Fragen zu stellen oder Dich mit Antworten hier zu beteiligen. Sei bitte auch nicht zurückhaltend mit der Bewertung und Kommentierung (was Du eh schon tust) von Fragen und Antworten. Die Community lebt von Partizipation. Sei ein Teil davon...
ffordermaier 06.06.2012

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH