Wie erfasst man den Ersatz einer (Property)Instanz?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

    Wie erfasst man den Ersatz einer (Property)Instanz?

    Hallo zusammen,

    im Thread EventHandler empfängt Eventfeuerung nicht zuverlässig habe ich es angedeutet: Ich will den Umgang mit der INotifyPropertyChanged-Schnittstelle vereinfachen. Dazu habe ich inzwischen folgendes:

    Die Basisklasse, welche man später abgeleitet nutzt:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public MustInherit Class SimpleNotifyingClass : Implements ComponentModel.INotifyPropertyChanged
    2. Public Event PropertyChanged As ComponentModel.PropertyChangedEventHandler Implements ComponentModel.INotifyPropertyChanged.PropertyChanged
    3. Protected Sub New()
    4. WireEvents()
    5. End Sub
    6. Private Async Sub WireEvents()
    7. Await Threading.Tasks.Task.Run(Sub() WaitForInitializing())
    8. For Each NotifyingProperty In Me.GetType.GetProperties.Where(Function(x) x.PropertyType.GetInterface(NameOf(ComponentModel.INotifyPropertyChanged)) IsNot Nothing)
    9. AddHandler DirectCast(NotifyingProperty.GetValue(Me), ComponentModel.INotifyPropertyChanged).PropertyChanged, AddressOf PropertyChangedEventReporter
    10. Next
    11. For Each MortalProperty In Me.GetType.GetProperties.Where(Function(x) x.PropertyType.GetInterface(NameOf(IMortal)) IsNot Nothing)
    12. AddHandler DirectCast(MortalProperty.GetValue(Me), IMortal).IsDying, AddressOf RegisterPropertyDeath
    13. Next
    14. End Sub
    15. Private Sub WaitForInitializing()
    16. Dim FirstNotifyingProperty = Me.GetType.GetProperties.FirstOrDefault(Function(x) x.PropertyType.GetInterface(NameOf(ComponentModel.INotifyPropertyChanged)) IsNot Nothing)
    17. If FirstNotifyingProperty Is Nothing Then Return
    18. Do Until FirstNotifyingProperty.GetValue(Me) IsNot Nothing : Loop
    19. End Sub
    20. Private Sub PropertyChangedEventReporter(sender As Object, e As ComponentModel.PropertyChangedEventArgs)
    21. RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs(String.Empty))
    22. End Sub
    23. Private Sub RegisterPropertyDeath(sender As Object, e As EventArgs)
    24. PropertyChangedEventReporter(Me, New ComponentModel.PropertyChangedEventArgs(String.Empty))
    25. End Sub
    26. End Class


    Die GenericProperty-Klasse
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class GenericProperty(Of T) : Implements ComponentModel.INotifyPropertyChanged, IMortal
    2. Public Event PropertyChanged As ComponentModel.PropertyChangedEventHandler Implements ComponentModel.INotifyPropertyChanged.PropertyChanged
    3. Public Event IsDying As EventHandler Implements IMortal.IsDying
    4. Private _Value As T
    5. Public Property Value As T
    6. Get
    7. Return _Value
    8. End Get
    9. Set
    10. If _Value.Equals(Value) Then Return
    11. _Value = Value
    12. NotifyPropertyChanged()
    13. End Set
    14. End Property
    15. Private Sub NotifyPropertyChanged(<Runtime.CompilerServices.CallerMemberName> Optional Name As String = Nothing)
    16. RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs(Name))
    17. End Sub
    18. Public Shared Widening Operator CType(Value As T) As GenericProperty(Of T)
    19. Return New GenericProperty(Of T) With {._Value = Value}
    20. End Operator
    21. Public Shared Widening Operator CType(Base As GenericProperty(Of T)) As T
    22. Return Base.Value
    23. End Operator
    24. Public Overrides Function ToString() As String
    25. If _Value Is Nothing Then Return Nothing
    26. Return _Value.ToString
    27. End Function
    28. Protected Overrides Sub Finalize()
    29. RaiseEvent IsDying(Me, Nothing)
    30. End Sub
    31. End Class

    Das Minihilfsinterface
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Interface IMortal
    2. Event IsDying As EventHandler
    3. End Interface


    Eine abgeleitete Klasse, die man im Hauptprogramm nutzen würde

    VB.NET-Quellcode

    1. Public Class Test : Inherits SimpleNotifyingClass
    2. Property ID As New GenericProperty(Of Integer)
    3. End Class


    die Verwendung

    VB.NET-Quellcode

    1. Dim TestInstance As Test = Nothing
    2. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. TestInstance = New Test
    4. BindingSource1.DataSource = TestInstance
    5. End Sub
    6. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    7. TestInstance.ID = 1
    8. GC.Collect()
    9. End Sub

    GC.Collect() ruft die GenericProperty-Finalize-Sub auf, die dann dafür sorgt, dass die GenericProperty der SimpleNotifyingClass bescheid gibt, dass sie ersetzt wurde, also dass das INotifyPropertyChanged.PropertyChanged-Event gefeuert werden muss und z.B. eine BindingSource davon erfährt. Das ist nicht besonders schön, aber erstmal die einzige Möglichkeit, wie ich dafür sorgen kann, dass die SimpleNotifyingClass-Instanz davon erfährt, dass eine bestehende Property ersetzt wurde.

    das Problem
    Die durch den überladenen Shared-Implicit-Cast-Operator CType erstellte neue Instanz muss jetzt irgendwie der SimpleNotifyingClass bescheid geben, dass sie existiert. Aber eben erst, wenn die bestehende Property ersetzt wurde. Nicht dass jemand schreibt:

    VB.NET-Quellcode

    1. Dim Foo As New GenericProperty(Of Integer) = 1
    und dass dann gar nicht an die SimpleNotifyingClass-Instanz weitergibt. Wie kann ich also den Ersatz der bestehenden SimpleNotifyingClass-Instanzproperty erfassen?
    Ich habe es natürlich schon mit einer ObservableCollection(Of INotifyPropertyChanged) probiert, aber das klappt (natürlich) nicht, da diese die Ersetzung nicht erkennt, wenn man ein Item der Collection direkt ersetzt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Ich bin einen kleinen Schritt weiter, auch wenn er mit unschönen Mitteln erreicht wurde.
    Das ist gleich geblieben: Wenn eine bestehende Property geändert wurde, indem man deren Value ändert, feuert sie selber das PropertyChanged-Event (im weiteren PCE), welches von der SimpleNotifyingClass (im weiteren SNC) abgefangen wird. Und diese feuert wiederum selber ein PCE, um die BindingSources zu informieren.

    Nun die Änderung: Das IMortal-Interface und somit auch das IsDying-Event sind raus. Stattdessen erfasst die SNC zu Beginn die HashCodes der Properties und prüft in festen Intervallen dieselbigen. Wird eine Property durch eine andere ersetzt, indem der überladene CType-Operator verwendet wird, hat die neue GenericClassProperty-Instanz definitiv einen anderen HashCode als die alte. Diese Änderung wird von der SNC-Prüfprozedur erkannt, sodass die SNC ihr eigenes PCE wieder feuern kann. Gleichzeitig merkt sich die SNC den neuen HashCode.

    Nun die weiterführende Fragen:
    1. Wie kann man das besser machen? Das nebenläufige, periodische Abfragen von HashCodes sollte keine nennenswerten Performanceeinbußen mit sich bringen. Aber irgendwie wurmt mich das trotzdem etwas. Geht das auch besser anders?
    2. Das GUI wird korrekt informiert, nur die Änderungen in z.B. einer TextBox rebellieren noch, da das entsprechende CE nicht mehr verlassen werden kann und auch das Beenden der App nicht mehr geht - außer über den Debugger. Offensichtlich scheitert der Versuch, den Propertyvalue über die BindingSource zu ändern.
    3. Offtopic: Ich vermute, dass auch ein FileSystemwatcher wie meine jetzige Lösung arbeitet, also periodisch den Zustand eines Verzeichnisses o.ä. abfragt. Macht er es intelligenter und könnte ich von seinem Verhalten etwas in mein Problem zur Lösung einfließen lassen?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Nebenläufig irgendwas überprüfen finde ich sehr unschön. Da sind explizite Get/Set Methoden schöner. Ich befürchte mal so wie du es vorhast, wird's nicht funktionieren. Um die Instanz der Propertyklasse zu kriegen musst du in den Setter der jeweiligen Instanz. So macht es Microsoft ja sowohl bei INotifyPropertyChanged, als auch bei DependencyProperties.
    Ich bin auch nicht sonderlich über die Lösung erfreut. Aber sie funktioniert. Deinen Vorschlag mit den Gettern/Settern verstehe ich insofern nicht, weil ich nicht weiß, wie das weitergehen soll. Wenn durch den Aufruf

    VB.NET-Quellcode

    1. TestInstance.ID.Value = 1
    der PropertySetter aufgerufen wird, ist alles gut. Wenn durch den Aufruf

    VB.NET-Quellcode

    1. TestInstance.ID = 1
    der CType-Operator eine neue GenericInstance(Of Integer) erstellt wird und damit die TestInstance.ID-Instanz überschrieben wird, habe ich ein Problem. Denn diese Ersetzung kann ich nicht abfangen. Daher sehe ich erstmal nur die periodische HashCodePrüfung als Weg, die Ersetzung zu detektieren. Wenn Du einen besseren Weg kennst, bin ich dafür offen. Das Problem ist, dass die neu erstelle GenericProperty-Instanz sich selbst nicht bei der SNC-Instanz anmelden kann. Auch kann die SNC-Instanz die neue GenericProperty-Instanz nicht erfassen. Würde ich einen GenericProperty-Konstruktor machen, der als Parameter die SNC-Instanz nimmt, damit die Verknüpfung zwischen den Instanzen hergestellt werden kann, klappt das mit dem CType-Operatoraufruf nicht mehr, da dieser Shared sein muss. Vor diesen Problemen stehe ich.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Um mein eigentliches Problem zu lösen, hat mich @exc-jdbi noch auf eine andere Variante hingewiesen, die mich am Ende zu dieser Seite geführt hat. In C# kann man da sehr gut den Property-BoilerPlateCode zusammenschmelzen lassen. Dafür die Basisklasse.
    Basisklasse

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Public MustInherit Class NotifyBase : Implements INotifyPropertyChanged
    3. Private ReadOnly propertyValues As Dictionary(Of String, Object)
    4. Protected Sub New()
    5. propertyValues = New Dictionary(Of String, Object)
    6. End Sub
    7. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    8. Protected Sub [Set](Of T)(value As T, <Runtime.CompilerServices.CallerMemberName> Optional name As String = Nothing)
    9. If propertyValues.ContainsKey(name) Then
    10. propertyValues(name) = value
    11. OnPropertyChanged(name)
    12. Else
    13. propertyValues.Add(name, value)
    14. OnPropertyChanged(name)
    15. End If
    16. End Sub
    17. Protected Function [Get](Of T)(<Runtime.CompilerServices.CallerMemberName> Optional name As String = Nothing) As T
    18. If (propertyValues.ContainsKey(name)) Then Return DirectCast(propertyValues(name), T)
    19. Return Nothing
    20. End Function
    21. Protected Sub OnPropertyChanged(propertyName As String)
    22. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    23. End Sub
    24. End Class

    Durch die VB.Net-Syntax komm ich dabei allerdings meinem Ziel nicht viel näher, da dann sowas rauskommt:

    VB.NET-Quellcode

    1. Public Class Test1 : Inherits NotifyBase
    2. Property ID As Integer
    3. Get
    4. Return [Get](Of Integer)()
    5. End Get
    6. Set
    7. [Set](Value)
    8. End Set
    9. End Property
    10. End Class
    Effektiv also keine deutliche Kürzung. Das Private Field verschwindet aus der abgeleiteten Klasse, genauso wie das PropertyChanged-Eventfeuern. Aber ich wollte ja mehr (oder weniger? Wie man möchte).

    Ich leg das Ganze jetzt erstmal auf Eis (≙ ich gebe auf und werde keine Energie mehr in das Vorhaben reinstecken*) und greife zu einem Trick, den ich ja schon verwende: Ich überprüfe einfach periodisch die PropertyValues der nun normalen Properties an sich. Damit ist mein Ziel durch eine dreckige Abkürzung erreicht, Stichwort KISS.
    Ziel mit Cheat

    VB.NET-Quellcode

    1. Public MustInherit Class SimpleNotifyingClass : Implements ComponentModel.INotifyPropertyChanged
    2. Public Event PropertyChanged As ComponentModel.PropertyChangedEventHandler Implements ComponentModel.INotifyPropertyChanged.PropertyChanged
    3. Private ReadOnly PropertyList As New Dictionary(Of Integer, Object)
    4. Protected Sub New()
    5. RememberAllProperties()
    6. InspectProperties()
    7. End Sub
    8. Private Sub RememberAllProperties()
    9. Array.ForEach(Me.GetType.GetProperties, Sub(x) PropertyList.Add(x.GetHashCode, x.GetValue(Me)))
    10. End Sub
    11. Private Async Sub InspectProperties()
    12. Do
    13. Await Threading.Tasks.Task.Delay(100)
    14. ReportChangedProperties()
    15. Loop
    16. End Sub
    17. Private Sub ReportChangedProperties()
    18. Dim KeyList = PropertyList.Select(Function(x) x.Key).ToList
    19. For Each Key In KeyList
    20. Dim SavedValue = PropertyList(Key)
    21. Dim [Property] = Me.GetType.GetProperties.First(Function(x) x.GetHashCode = Key)
    22. Dim CurrentValue = [Property].GetValue(Me)
    23. If Not ThereAreChanges(SavedValue, CurrentValue) Then Continue For
    24. PropertyList.Item(Key) = CurrentValue
    25. ReportPropertyChanged([Property].Name)
    26. Next
    27. End Sub
    28. Private Function ThereAreChanges(SavedValue As Object, CurrentValue As Object) As Boolean
    29. Return SavedValue Is Nothing AndAlso CurrentValue Is Nothing OrElse SavedValue IsNot Nothing AndAlso SavedValue.Equals(CurrentValue)
    30. End Function
    31. Private Sub ReportPropertyChanged(PropertyName As String)
    32. RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs(PropertyName))
    33. End Sub
    34. End Class

    Jetzt kann ich ganz normal schreiben

    VB.NET-Quellcode

    1. Public Class FrmMain
    2. Dim TestInstance As Test = Nothing
    3. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. TestInstance = New Test
    5. BindingSource1.DataSource = TestInstance
    6. End Sub
    7. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    8. TestInstance.ID = 123
    9. TestInstance.SomeNumber = 666
    10. TestInstance.Name = "VaporiZed"
    11. TestInstance.DateOfBirth = Date.Today.AddDays(10).AddYears(-99)
    12. End Sub
    13. End Class
    14. Public Class Test : Inherits SimpleNotifyingClass
    15. Property ID As Integer
    16. Property SomeNumber As Integer
    17. Property Name As String
    18. Property DateOfBirth As Date
    19. End Class
    und wenn sich eine Property ändert, wird die BS spätestens nach knapp 100 ms informiert und updatet das GUI.

    * Das Problem ist auch gewesen, dass die Anbindung an ein Control zwar funktionierte, aber das Wertändern nicht mehr (oder nur mit Konvertierzeilen im Validating-EventHandler). Das war mir dann zu blöde.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hi!

    Ich staune ja seit kurzem einige deiner Threads an, die iwas mit INotifyPropertyChanged zu tun haben, und ich versteh nicht was du willst.
    Mein derzeitiger Vermutungs-Stand ist: Du möchtest von dem lausigen Zwang wegkommen, beim Implementieren von INotifyPropertyChanged für jede Property 9(!) Zeilen vb.net-Code aufzuwenden - wie:

    VB.NET-Quellcode

    1. '--------------
    2. ' T4-generated file - don't mess it up
    3. '--------------
    4. Imports System, System.ComponentModel, System.Linq, System.Collections.Generic, System.Collections.ObjectModel
    5. Namespace BestellungenEdm
    6. Public Class BestellPosten : Inherits NotifyPropertyChanged
    7. Private _Id As Integer
    8. Public Property Id As Integer
    9. Get
    10. Return _Id
    11. End Get
    12. Set(ByVal value As Integer)
    13. ChangePropIfDifferent(value, _Id)
    14. End Set
    15. End Property
    16. Private _Count As Integer
    17. Public Property Count As Integer
    18. Get
    19. Return _Count
    20. End Get
    21. Set(ByVal value As Integer)
    22. ChangePropIfDifferent(value, _Count)
    23. End Set
    24. End Property
    25. '...
    Das ist jetzt das absolute Minimum an Code-Aufwand, was in vb.net möglich ist: 9 Zeilen: nämlich eine Zeile Backingfield deklarieren, 2 Zeilen die Property, 3 Zeilen der Getter darin, 3 Zeilen der Setter.
    Das ist tatsächlich super-lausig, weils tausendfach sich wiederholender Boiler-Plate-Code ist - aber wie gesagt: Ich habe bislang nix kompakteres gefunden.

    Zunächst aber zwei Fragen:
    • Habich die Problematik endlich verstanden?
    • Wenn ja: habich was zu lesen übersehen, oder steht das bislang tatsächlich nirgends?

    Wie dem auch sei, und falls das tatsächlich das Thema ist: Daran habich mir auch schon einige Zähne ausgebissen, und nix wirklich überzeugendes gefunden.
    Mir sind derzeit mehrere Umgänge damit bekannt
    • Fody
      Man kann sich iwie eine Fody-Extension oder AddOn runterladen und iwie einbinden, welcher den Boiler-Plate-Code injiziert, noch nachdem die Klasse in IL übersetzt ist. Oder so ähnlich - ich habs nie gemacht wegen der zusätzlichen Abhängigkeit, und weil wenn ich solchen Code verteile, das die Empfänger zwingen würde, sich auch Fody raufzuschaffen - sonst würde mein Code bei denen nicht laufen
    • CodeGenerierung
      siehe obiges Beispiel: Ich hab mir ein irrwitziges T4-Template geschrieben für *.edmx-Dateien. Nun kann ich Datenklassen in .edmx-Designern designen, und das T4 generiert mir Designer-Code wie oben gezeigt.
      CodeGenerierung, die INotifyPropertyChanged unterstützt, findet ja auch bei Verwendung typisierter Datasets statt - mein *.edmx-T4-Template brauche ich für Wpf-Entwicklung - wo Dataset-Databinding ja nicht richtig funktioniert.
    • noch mehr CodeGenerierung
      man könnte auch einen Codegenerator schreiben, der CodeFiles untersucht, und wenn sie ein bestimmtes Attribut aufweisen, dasser dann alle Auto-Properties darin umschreibt
    • Regions
      um diese "neun-Zeilen-statt-einer"-Schaurigkeiten nicht angucken zu müssen kann man auch mit Regions arbeiten.
    • Partiale Klassen
      Von Regions halte ich eiglich nix - ich würde derlei Code in Partiale Klassen wegsperren
      Kann man sich überlegen, ob man die Backing-Fields nicht in der richtigen Logik-Datei belässt - damit man dort auch sieht, welche Properties die Klasse bereitstellt.
    • Self-Change-Polling
      Das ist jetzt wie ich benennen würde, was ich von deinem Ansatz zu verstehen meine: Die Datenklasse stellt Property-Änderungen nicht mehr direkt im Setter fest und reagiert, sondern unterhält für jede Auto-Property (irgendwo) ein zweites BackingField, um es dann pollend mit dem "richtigen" BackingField zu vergleichen, und so Property-Änderungen feststellen und drauf reagieren.

      spannender Ansatz, weil dabei der Code-Ablauf beim Databinding sich stark ändert. Standard-Databinding funktioniert bislang blockierend - also eine Property-Änderung löst direkt EventCode aus, und da kann u.U. sehr viel passieren. Weiter gehts aber erst, wenn das alles passiert ist.
      Mit deim Ansatz gehts sofort weiter, und das Event-Auslösen erfolgt zeitverzögert.
      Das muss nicht unbedingt ein Nachteil sein - vielleicht hat das in bestimmten Szenarien sogar Vorteile.
      Vermutlich (hoffentlich) wird man den Unterschied aber kaum merken.

      Nachteile wären jedenfalls erhöhter Speicherbedarf und Prozessorlast, sowie schlechtere Performance - aber das sollte man erstmal abwarten, wie dolle das zu Buche schlägt.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    Mein derzeitiger Vermutungs-Stand ist
    …korrekt.
    Und das habe ich geschafft, mit PropertyValuePolling. Nicht schön, aber funktioniert.

    ErfinderDesRades schrieb:

    Habich die Problematik endlich verstanden?
    Ja.
    Zu Deinen Lösungsansätzen:
    • externe Codegenerierung: Ist nicht meins.
    • Regions: Ich verabscheue vermeide Regions (auch wenn ich es in meinem Tut als Möglichkeit erwähne)
    • Partiale Klassen: War auch mein Vorschlag in meinem Tut bei 4.1 - Nachteile
    ##########

    ErfinderDesRades schrieb:

    habich was zu lesen übersehen, oder steht das bislang tatsächlich nirgends?
    Weiß nicht, was Du meinst. In Post#1 in den ersten beiden Spoilern ist je die erste Zeile mit Implements ComponentModel.INotifyPropertyChanged versehen. Oder ich versteh Dich falsch.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    VaporiZed schrieb:

    externe Codegenerierung: Ist nicht meins.
    Echt nicht?
    Bzw was verstehst du unter externe CodeGenerierung?
    1. Wenn du ein WinForms designest verwendest du ja auch CodeGenerierung - wäre die "extern"?
    2. Beim typDataset ists das gleiche wie WinForms
    3. Bei Verwendung von *.Edmx ists fast das gleiche: Ein Designer generiert Code - das T4-Template dafür ist Voreinstellung
    4. Aber man kann bei *.edmx das T4 auch auswählen (meine Wpf-Variante) - wäre das dann "extern"?
    5. Oder ein selbstgebasteltes Tool drüber laufen lassen. Das wäre in gewissem Sinne auch keine CodeGenerierung, sondern ist eiglich wie alles selbst ausschreiben.
      Weil andere kriegen ja nur das Ergebnis, und haben auch keinen Designer, mit dem sie mein Ergebnis versehentlich kaputt machen könnten.
    6. oder meinst du mit "extern" nur den Fody?
    Also 1. ist wohl deins. Bei 2. glaub ich aber doch, bin aber nicht sicher - evtl. verwendest du typDts garnet.
    Also welche der 6 CodeGenerierungs-Varianten sind "extern", und also "nicht deins"?
    Ok, schlecht formuliert. Ich habe nicht vor, irgendwelche Plugins wie Fody oder PostSharper zu nutzen, sondern das Ziel mit Hausmitteln zu erreichen. Mit T4 habe ich mich nur anfänglich beschäftigt. tDS benutz ich nicht mehr bzw. baue gerade um. Denn dortige Veränderungen werden ja sofort im GUI gezeigt. Da brauche ich ja meinem Bastelkram nicht, würde ich das weiternutzen. Aber einige tDS-Aspekte sagen mir nicht mehr zu, daher wende ich mich davon ab.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Dein "Problem" mit Polling zu lösen halte ich für absolut keine gute Idee. Die Performanceimplikationen von den ständigen wiederholten Gleichheitsabfragen können schnell immens werden und ganz abgesehen von den direkten Auswirkungen hiervon hast du zusätzlich noch die Verzögerung, weil du nur alle 100ms + Prüfzeit die UI/... aktualisierst. Das alles Mal abgesehen davon, dass das sowieso ne richtig unsaubere Lösung ist.

    Wenn dich die Property-Bodies im Code so extrem stören, mach dir doch, ähnlich wie EDR angedeutet hat, ne Codegenerierung, die dir den Code in ner partiellen Klasse dazugeneriert (geht mit VS-eigenen Tools) und wenn's nur ums Schreiben geht, mach dir nen Snippet in VS, was den Code für dich schreibt.
    Und wenn du nichts gegen externe Dependencies hast, ist Fody ne super Lösung - das PropertyChanged-Addin von denen macht das auf ne saubere Art und Weise automatisch, ohne dass was konfiguriert werden muss.
    Ich verstehe den Gedankengang und ich kan verstehen das man wenig Code haben will, insbesonders bei den Properties.

    Allerdings muss ich sagen.... ich würde auch wenn es denn eine vernünftige Möglichkeit gibt hier ein Propertie ohne Backingfield definieren zu können NIE zu dieser Lösung greifen.
    Warum? Ja, zum einen muss ich den code ja garnicht schreiben. Das macht mir eh VS. prop + TAB + TAB. Fertich. Und zum anderen kann ich jederzeit einen Haltepunkt z.b. im Seter setzen um zu sehen was passiert, das ist etwas was ich nicht missen möchte.

    Ein weiterer Grund ist aber auch das man bei korrektem MVVM dann auch sehr häufig Klassen hat welche ein Model-Objekt Wrappen in welchen die Lösung dann sowieso wieder nicht zu gebrauchen ist.

    Beispiel:

    VB.NET-Quellcode

    1. Public Class Auto
    2. Public Property Marke As String
    3. Public Property Modell As String
    4. Public Property KW As Double
    5. End Class
    6. Public Class AutoViewModel
    7. Inherits ViewModelBase
    8. Private ReadOnly _carModel As Auto
    9. Public Sub New(_car As Auto)
    10. _carModel = _car
    11. End Sub
    12. Public Property Marke() As String
    13. Get
    14. Return _carModel.Marke
    15. End Get
    16. Set(ByVal value As String)
    17. _carModel.Marke = value
    18. RaisePropertyChanged()
    19. End Set
    20. End Property
    21. Public Property Modell() As String
    22. Get
    23. Return _carModel.Modell
    24. End Get
    25. Set(ByVal value As String)
    26. _carModel.Modell = value
    27. RaisePropertyChanged()
    28. End Set
    29. End Property
    30. Public Property PS() As String
    31. Get
    32. Return _carModel.KW * 1.36
    33. End Get
    34. Set(ByVal value As String)
    35. _carModel.KW = value / 1.36
    36. RaisePropertyChanged()
    37. End Set
    38. End Property
    39. End Class


    Und zu guter letzt habe ich mir in VS sowieso meine Vorlagen eingerichtet. Statt prop tippe ich wpfprop + TAB + TAB und bekomme ein Propertie inkl. den RaisePropertyChanged() generiert.

    Das ist meine Meinung und soll nun natürlich nicht so gesehen das ich das wem einreden möchte, ich denke mir nur das es wenig sinn macht.
    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##