Autor Beitrag
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 06.08.16 02:13 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Sa 06.08.16 09:48 
Hallo,

mit einem struct wird es vermutlich gar nicht gehen, weil der ja kein Referenzdatentyp ist und an Kopien gearbeitet wird. Bei einer Klasse musst Du Deinen eigenen TypeConverter schreiben. Das ist hier ganz gut gezeigt: social.msdn.microsof...ygrid?forum=winforms

Im Prinzip so (anhand Deiner frListView-Komponente, die ich noch in meiner Test-Umgebung hatte :D)
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
    public class frListView : ListView
    {
        [TypeConverter(typeof(MySettingsTypeConverter))]
        public class MySettings
        {
            [Browsable(true)]
            public int Setting1 { get; set; }
            [Browsable(true)]
            public string Setting2 { get; set; }
        }


        public class MySettingsTypeConverter : TypeConverter
        {
            public override object ConvertTo(ITypeDescriptorContext context,
            System.Globalization.CultureInfo culture, object value, Type destinationType)
            {//This method is used to shown information in the PropertyGrid.
                if (destinationType == typeof(string))
                {
                    return ((MySettings)value).Setting1.ToString() + "," + ((MySettings)value).Setting2;
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }

            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
            {
                return TypeDescriptor.GetProperties(typeof(MySettings), attributes).Sort(new string[] { "Setting1""Setting2" });
            }

            public override bool GetPropertiesSupported(ITypeDescriptorContext context)
            {
                return true;
            }
        }

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public MySettings MySetting { get; private set; }

        public frListView()
        {
            MySetting = new MySettings();
        }

/* ... */


Die ListView hat jetzt eine im Properties-Fenster editierbare Eigenschaft "MySetting" vom Typ "MySettings". Damit das Properties-Window weiß, was es zu tun hat, gibt es den TypeConverter, der vor allem für die String-Darstellung sorgt und eine Liste mit editierbaren Properties zurückgibt.

Viele Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 06.08.16 10:13 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Sa 06.08.16 11:40 
Nochmal wegen dem Struct:
Ein Struct ist fast immer eine ganz schlechte Idee
Hier findest Du weiter unten eine Checkliste, wann man Structs nehmen kann/sollte
Diese Punkte habe ich bisher aber noch nie sinnvoll erfüllt gesehen, außer bei .NET eigenen Typen wie Point, Size oder DateTime.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 06.08.16 12:14 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Sa 06.08.16 12:17 
Zitat:
Diese Punkte habe ich bisher aber noch nie sinnvoll erfüllt gesehen, außer bei .NET eigenen Typen wie Point, Size oder DateTime.


Eigentlich scheitert Microsoft fast immer an der immutability (auch Point&Size) ;) Außer vielleicht bei elementaren Typen die man für Basistypen halten könnte wie DateTime. Und wenn sie es richtig machen sind die Leute doch nicht zufrieden weil es andere ~Dinge~ verhindert. Z.B die ~richtige~ struct Implementierung von KeyValuePair die Serialisieren von Dictionarys problematisch macht.
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Sa 06.08.16 14:48 
Point ist veränderbar?
In meinem Verständnis sollte alles ein Struct sein, das einen einzelnen Wert darstellt, wie die Zahl 5 eben immer und nur die Zahl 5 sein kann.
Ein Punkt an den Koordinaten 12 und 13 wird immer diese Koordinaten haben, sonst ist es ein anderer Punkt.
Bei Size - gut, da wäre eine Klasse vermutlich doch die bessere Wahl, aber bei WPF haben sie die Size-Property ja auch raus geworfen und belassen aus bei Width und Height.
Warum KeyValuePair ein Struct ist, verstehe ich gar nicht :D


@Frühlingsrolle:

Ich kenne Objective Pascal nicht, den Code aus dem Link kapier ich auch nicht so wirklich :D
Der TypeConverter hat aber an sich nichts damit zu tun, dass unter C# etwas nicht oder nur anders lösbar ist, sondern dass der TypeConverter von Controls wie dem PropertyGrid verwendet wird um die Eingabe von dem Benutzer richtig zu konvertieren.
Das ist das Problem bei Controls, die so viel automatisch machen, Du gibst massiv Kontrolle ab, weil Du dadurch ebenfalls massiv Arbeit sparst.
Der TypeConverter soll bei der Arbeit die Möglichkeit bieten, einen Teil dieser Kontrolle zurück zu bekommen.

Ein Beispiel, das ich letztens gebraucht habe:
Ich hatte ein int-Array, das in dem PropertyGrid angezeigt werden soll. Dort wird das automatisch über ein zweites Fenster zugänglich gemacht, über das man dann einzeln Zahlen hinzufügen oder entfernen kann. Wie ich finde eine denkbar unschöne Variante, ich brauch doch kein eigenes kleines Fenster um ein paar Zahlen zu definieren.
Meine TypeConverter-Lösung hat das ganze erweitert, indem der Nutzer zusätzlich die Zahlen kommagetrennt schreiben kann und die Zahlen dann als int-Array konvertiert und verwendet werden.
Das ließe sich allerdings auch so lösen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
[Browsable(false)]
public int[] Array { get; set; }

[Browsable(true)]
[DisplayName("Array")]
public string ArrayString
{
    get { return string.Join(",", Array); }
    set { Array = value.Split(',').Select(int.Parse).ToArray(); }
}


Angezeigt wird dann die Property ArrayString unter dem Namen Array, die eigentliche Array-Property ist gar nicht sichtbar, wird aber trotzdem korrekt gefüllt.
Soweit ich das beurteilen kann, kommt das denke ich dem Beispiel aus dem Link am nächsten?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Sa 06.08.16 15:17 
Zitat:
Ein Punkt an den Koordinaten 12 und 13 wird immer diese Koordinaten haben, sonst ist es ein anderer Punkt.


So sollte es sein und die Implementierung von Point als struct täuscht das auch vor. Trotzdem haben die Koordinaten von Point einen setter und implizieren was anderes und Programmierer werden deswegen glauben es wäre sinnvoll änderbar. structs + setzbare Properties sind immer ein Design Problem. Manchmal vielleicht nötig und das Point/Size so gebaut sind wie sie sind hat möglicherweise einen technischen Grund aus dem Framework heraus. Der erschließt sich mir aber rein logisch erstmal nicht so das ich ihn gerade nicht benennen kann.
Das war übrigens auch der einzige Punkt :D den ich setzen wollte. Du stelltest Point/Size als positive Beispiele heraus wie man struct implementieren sollte. Das sind sie sicher nicht. Wenn man structs implementiert dann ohne Setter für Properties (als echten immutable Typ). Zumindest sollte man es nicht grundlos tun.
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Sa 06.08.16 15:27 
Ok, ich entschuldige mich für diese Fehlinformation :/

Ich wusste bis jetzt nicht einmal, dass die Setter haben O.o
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Sa 06.08.16 15:35 
Zitat:
Ok, ich entschuldige mich für diese Fehlinformation


Kein Problem und auch kein Vorwurf von mir. Wie, wo, warum structs ist ein spannendes und problematische Thema.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 08.08.16 04:22 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 08.08.16 08:11 
Wie meinst Du das?

Solange der TypeConverter den Typ der Property in den Ziel-Typ (beim PropertyGrid wäre es dann wohl String) konvertieren kann, kannst Du den so oft nutzen wie Du willst.
Das Attribute TypeConverter definiert ja nur, wo der COnverter zu finden ist, das PropertyGrid erzeugt sich den dann selber.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 08.08.16 09:47 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 08.08.16 10:16 
Schreib dir doch eine Basis-Klasse?
Die hat dann z.B. zwei abstrakte Methode "GetSetting1" und "GetSetting2"
Der Rest kann ja gleich bleiben
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 08.08.16 13:24 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mo 08.08.16 14:46 
Vermutlich kann man die verschiedenen Einstellungstypen ein gemeinsames Interface implementieren lassen und dann einen generischen TypeConverter schreiben, der für alle Typen funktioniert, die dieses Interface implementieren. Wenn bis dahin keine bessere Lösung kommt, schreibe ich da heute abend mal was für zusammen.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 08.08.16 17:49 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mo 08.08.16 18:48 
Hallo,

so habe ich mir das gedacht:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
[TypeConverter(typeof(GenericTypeConverter<MySettings>))]
    public class MySettings : ITypeConvertible
    {
        [Browsable(true)]
        public int Setting1 { get; set; }
        [Browsable(true)]
        public string Setting2 { get; set; }

        public string[] GetProperties()
        {
            return new string[] { nameof(Setting1), nameof(Setting2) };

        }

        public string GetPropertiesAsString()
        {
            return $"{Setting1}, {Setting2}";
        }
    }

    public interface ITypeConvertible
    {
        string[] GetProperties();
        string GetPropertiesAsString();
    }

    public class GenericTypeConverter<T> : TypeConverter where T : ITypeConvertible
    {
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (value.GetType() != typeof(T))
                throw new ArgumentException($"{nameof(value)} has the wrong type.", nameof(value));

            if (destinationType == typeof(string))
            {
                return ((T)value).GetPropertiesAsString();
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }

        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            if (value.GetType() != typeof(T))
                throw new ArgumentException($"{nameof(value)} has the wrong type.", nameof(value));

            return TypeDescriptor.GetProperties(typeof(T), attributes).Sort(((T)value).GetProperties());
        }

        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            return true;
        }
    }


Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 08.08.16 21:12 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 11.08.16 00:41 
- Nachträglich durch die Entwickler-Ecke gelöscht -