Jeder kennt das im Visual Studio verwendete Eigenschaftsfenster und das darin liegende Steuerelement für die Manipulation der Objekteigenschaften (Properties). Man findet es in der Toolbox unter “Alle Windows Forms”.
- Zunächst ein Beispielobjekt, ein Auto 🙂
using System.ComponentModel; public enum ECarType { [Description("ohne Dach")] Cabriolet, [Description("mit Dach")] Stufenheck, [Description("mit Rucksack")] Combi } // Beispiel-Klassenstruktur für das später im PropertyGrid zu editierende Objekt // DefaultPropertyAttribute legt fest, dass Tyres standardmäßig ausgewählt ist [DefaultPropertyAttribute("Tyres")] public class CCar { private int iTyres = 4; private string sManufacturer = "Horch"; private string sCarImage = string.Empty; private Color clCarColor = Color.Black; private List<double-> lConsumption = new List<double->(); private ECarType eCarType = ECarType.Stufenheck; // das Auto hat eine bestimmte Anzahl Räder // mögliche Attribute für die Steuerung der PropertyGrid-Eigenschaften: // // Browsable - Objekteigenschaft im PropertyGrid anzeigen? // DefaultValue - Standardwert für die Eigenschaft, wenn kein Wert gesetzt // Description - Hilfetext für das Hilfefenster // Category - Kategorie (Gruppe) für die Sortierung der Eigenschaften // ReadOnly - steuert "nur Lesen" Eigenschaft // DefaultProperty - Eigenschaft als Standardeigenschaft, wird dann automatisch bei der Anzeige ausgewählt // DisplayName - angezeigter Propertyname [Browsable(true), DefaultValue(4), Description("Anzahl der Reifen"), Category("Allgemein"), DisplayName("verwendete Reifen")] public int Tyres { get { return iTyres; } set { iTyres = value; } } // das Auto hat natürlich einen Hersteller [Browsable(true), DefaultValue("Horch"), Description("Name des Herstellers"), Category("Allgemein"), DisplayName("Hersteller des Autos")] public string Manufacturer { get { return sManufacturer; } set { sManufacturer = value; } } // das Auto soll ein Bild zugeordnet bekommen // zur späteren komfortablen Bildauswahl soll ein Fileauswahl-Dialog angezeigt werden // dazu sollte sich eine eigene Klasse 'CFileNameEditorHelper' abgeleitet werden (s.u.) [Editor(typeof(CFileNameEditorHelper), typeof(System.Drawing.Design.UITypeEditor))] [Browsable(true), DefaultValue(""), Description("Autobild"), Category("Grafik"), DisplayName("kleines Vorschaubild")] public string CarImage { get { return sCarImage; } set { sCarImage = value; } } // Farbe des Autos, Farbauswahl wird automatisch angezeigt [Browsable(true), Description("Autofarbe"), Category("Grafik"), DisplayName("Farbe des Autos")] public Color CarColor { get { return clCarColor; } set { clCarColor = value; } } // Verbrauchstabelle als Liste // hier wird ein eigenes Editorfenster benötigt (ConsumptionListEditor), dieser muss extra definiert werden (s.u.) // über den TypeConverter wird einfach der Anzeigename der Liste in "Datenwerte" angepasst [Editor(typeof(ConsumptionListEditor), typeof(System.Drawing.Design.UITypeEditor))] [Browsable(true), Description("Liste mit Verbräuchen"), Category("Kurven"), DisplayName("Verbrauch")] [TypeConverter(typeof(MyListConverter))] public List<double-> Consumption { get { return lConsumption; } set { lConsumption = value; } } // Beispiel für Verwendung von Enum, Klasse für die Umwandlung bzgl. CarTypeConverter s.u. [Browsable(true), Description("beschreibt den Autotyp"), Category("Allgemein"), DisplayName("Typ des Autos")] [TypeConverter(typeof(CarTypeConverter))] public ECarType CarType { get { return eCarType; } set { eCarType = value; } } public CCar() { } }
- Hilfsklasse für die Bildauswahl
// zuvor noch Assembly System.Design unter Verweise->Verweis hinzufügen dem Projekt hinzufügen using System.Windows.Forms.Design; // Eigene abgeleitete FileEditor-Klasse für die Bildauswahl public class CFileNameEditorHelper : FileNameEditor { public CFileNameEditorHelper() { } // InitializeDialog überschreiben protected override void InitializeDialog(System.Windows.Forms.OpenFileDialog openFileDialog) { // Basisdialog initialisieren base.InitializeDialog(openFileDialog); // hier die benötigten Properties des Auswahldialoges setzen openFileDialog.CheckFileExists = true; openFileDialog.ShowReadOnly = false; openFileDialog.Title = "Bitte ein Bild auswählen"; openFileDialog.Filter = "BMP (*.bmp)|*.bmp|JPG (*.jpg)|*.jpg|PNG (*.png)|*.png|GIF (*.gif)|*.gif|Alle Dateien (*.*)|*.*"; openFileDialog.DefaultExt = ""; openFileDialog.FileOk += new System.ComponentModel.CancelEventHandler(openFileDialog_FileOk); } // Eventhandler für das Schließen des File-Dialoges void openFileDialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e) { // sender ist unser Dialog System.Windows.Forms.OpenFileDialog fd = sender as System.Windows.Forms.OpenFileDialog; if (fd != null) { // hier kann noch etwas mit dem Filedialog veranstaltet werden, // z.B. wenn man nur den Filenamen ohne Pfad extrahieren will // fd.FileName = Path.GetFileName(fd.FileName); } } }
- Hilfsklasse für den Listeneditor
// zuvor noch Assembly System.Design unter Verweise->Verweis hinzufügen dem Projekt hinzufügen using System.Windows.Forms.Design; // eigene ListEditor-Klasse für das Editieren einer Liste public class ConsumptionListEditor : UITypeEditor { // Editstyle des Dialoges festlegen public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.Modal; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { if ((context != null) && (provider != null)) { IWindowsFormsEditorService svc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (svc != null) { // eigenen Dialog erzeugen und anzeigen // im Beispiel wird im Konstruktor des Dialoges die Referenz der Liste mit übergeben frmDataCurve dialog = new frmDataCurve(value as List<double->); // Dialog anzeigen und Result abfragen if (svc.ShowDialog(dialog) == System.Windows.Forms.DialogResult.OK) { } } } return value; } }
- Hilfsklasse für CarTypeConverter
prublic class CarTypeConverter : EnumConverter { private Type _enumType; public CarTypeConverter(Type type) : base(type) { _enumType = type; } public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) { return (destType == typeof(string)); } public override bool CanConvertFrom(ITypeDescriptorContext context, Type srcType) { return (srcType == typeof(string)); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType) { FieldInfo fi = _enumType.GetField(Enum.GetName(_enumType, value)); DescriptionAttribute dna =(DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); if (dna != null) return dna.Description; else return value.ToString(); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { foreach (FieldInfo fi in _enumType.GetFields()) { DescriptionAttribute dna = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); if ((dna != null) && ((string)value == dna.Description)) return Enum.Parse(_enumType, fi.Name); } return Enum.Parse(_enumType, (string)value); } }
- Hilfsklasse für TypeConverter der Liste
// zuvor noch Assembly System.Design unter Verweise->Verweis hinzufügen dem Projekt hinzufügen using System.Windows.Forms.Design; public class MyListConverter : TypeConverter { public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType) { // wenn Liste mit Double-Werten if (destType == typeof(string) && value is List<double->) { return "Datenwerte"; } // sonst Standardkonvertierung return base.ConvertTo(context, culture, value, destType); } }
- Anwendungsbeispiel
// Beispielobjekt erzeugen CCar Car = new CCar(); // dem PropertyGrid ein Objekt zum Editieren zuordnen // propertyGrid1 - das verwendete PropertyGrid // Car - das zu editierende Objekt propertyGrid1.SelectedObject = Car; // im Propertygrid 'propertyGrid1' werden nun die Properties 'Tyres', 'Manufacturer' und 'CarImage' // in den jeweiligen Gruppen 'Allgemein' und 'Grafik' angezeigt // für die Auswahl der Property 'CarImage' wird ein FileDialog bereitgestellt // Eingaben werden typabhängig geprüft und in das Objekt zurückgeschrieben
Eine detailliertere Beschreibung für die Verwendung eines PropertyGrids findet man bei:
Using PropertyGrid control in .NET
Customized display of collection data in a PropertyGrid