Selbe Logik in mehreren Formen

  • VB.NET

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von sonne75.

    Selbe Logik in mehreren Formen

    yo Leute,

    steh irgendwie grad ein wenig am Schlauch.
    Bei einem Projekt hab ich nun 2 Formen erstellt welche im Grunde genommen verschiedene Sachen behandeln (logisch).
    Jedoch ähneln diese 2 (und auch die die noch folgen werden) in gewisser Weise ja doch.
    z.B. haben alle Formen oben einen Toolstrip mit immer den selben Symbolen. Das Beste daran ist, dass die Click Methoden sogar den selben Code ausführen (Speicher, Neuer Eintrag, Abbrechen, ...)
    Zusätzlich werden diese per Code teilweise Enabled True/False gesetzt (was auch für alle Formen gleich wäre).

    Nun will ich nicht in jede Form den selben Code schreiben, da er sich sehr ähnlich ist (nicht zu 100% aber halt hast).

    Wie gehe ich hier am Besten vor? In eine Klasse kann ich den Code nur umständlich auslagern, da ich ja für jeden Toolstrip Button eine eigene Property benötigen würde.
    Zusätzlich müsste ich manche Methoden aber auch überschreiben, da in einer anderen Form auch andere Controls sein können welche diese Methode bearbeitet.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    @fichz:: Gib beiden Formen eine von Form abgeleitete "Zwischen"-Basisklasse, wo Du den Code reinschreibst.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das hatte ich als erstes versucht aber ich bekomm anschließend einen Designer Fehler.

    Der Designer konnte für diese Datei nicht angezeigt werden, da keine der enthaltenen Klassen definiert werden kann. Der Designer hat folgende Klassen in der Datei überprüft:
    Form1 -- Die WindowsApplication1.FormBase-Basisklasse konnte nicht geladen werden. Stellen Sie sicher, dass auf die Assembly verwiesen wurde und alle Projekte erstellt wurden.


    Gemacht hab ich nur:

    VB.NET-Quellcode

    1. Public Class FormBase
    2. Inherits Form
    3. End Class


    In der eigentlichen (nackten) Form1

    VB.NET-Quellcode

    1. Public Class Form1
    2. Inherits WindowsApplication1.FormBase
    3. End Class


    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    fichz schrieb:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Inherits WindowsApplication1.FormBase
    3. End Class
    Hier kannst Du das WindowsApplication1, allerdings richtet es keinen Schaden an, sofern Du die Klasse nicht anderweitig nutzest.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich denke mein Vorhaben scheitert nun an etwas was man nicht ändern kann.
    Ziel war es diverse Methoden als MustOverride zu kennzeichnen, was jedoch dazu führt, dass man die FormBase Klasse als Abstrakt kennzeichnen muss, was wiederrum dazu führt, dass abgeleitete Formen nicht mehr im Designer angezeigt werden können, da keine Instanz der FormBase erstellt werden kann (MustInherit).

    Muss mir hierzu was anderes überlegen :S

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    fichz schrieb:

    MustOverride
    Dann wirf doch in dieser Klasse einfach eine entsprechende Exception
    oder
    bau Dir ein entsprechendes Interface parallel zu FormBase.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ja hab ich versucht und funktioniert auch (wenn auch irgendwie nur teilsweise).
    Ich werde das Auslagern jetzt sein lassen, da es sich, wie sich herausstellte, es teilweise in fast jeder Prozedur was geändert werden muss.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    und dann gibts noch den sog. "Behavior-Pattern".
    Das sind Klassen, denen übergibt man ein Objekt, und die abonnieren dann dessen Events und reagieren entsprechend.

    vlt. kommst du ja mit einer einzigen Form-Klasse aus, deren Instanzen du nur verschiedene Behaviors andrehst.
    @~blaze~: Wenn ich das richtig verstehe sollte ich eine abstrakte Basisklasse machen für all die Sachen die wirklich gleich sind, und alle anderen (wie Speichern, etc) was sich ändern als MustOverride deklareren.
    Das mit der Property weiß ich nicht ganz wie du das meinst. Soll dann im Set Teil der Konstruktur aufgerufen werden?

    @ErfinderDesRades: Diesen Pattern muss ich mir mal ein bisschen anguggen. Hört sich so gesehen auch ganz intresannt an :)

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    fichz schrieb:

    eine abstrakte Basisklasse
    brauchst Du für Sachen, die gleich behandelt werden sollen, aber unterschiedlich implementiert sind.
    Identische Prozeduren gehören in eine "normale" Basisklasse.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Auch "identische Prozeduren" können in eine abstrakte Basisklasse. Dass eine Basisklasse abstrakt ist, bedeutet nur, dass sie nicht instanziert werden kann, Objekte also nur aus davon abgeleiteten Klassen erzeugt werden können.
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.
    So:

    VB.NET-Quellcode

    1. Public Class SomeForm
    2. Inherits Form
    3. Private _executionContext As SomeExecutionContext
    4. Public Property ExecutionContext As SomeExecutionContext
    5. Get
    6. Return _executionContext
    7. End Get
    8. Private Set(value As SomeExecutionContext)
    9. _executionContext = value
    10. OnExecutionContextChanged(EventArgs.Empty)
    11. End Set
    12. End Property
    13. Protected Overridable Sub OnExecutionContextChanged(e As EventArgs)
    14. UpdateExecutionContext()
    15. End Sub
    16. Private Sub UpdateExecutionContext()
    17. _saveAsMenuItem.Enabled = executionContext.CanSave
    18. End Sub
    19. Protected Sub New()
    20. InitializeComponent()
    21. ExecutionContext = ExecutionContext.Default
    22. End Sub
    23. Public Sub New(executionContext As SomeExecutionContext)
    24. Me.New()
    25. ExecutionContext = If(executionContext, ExecutionContext.Default)
    26. End Sub
    27. Private Sub _saveAsMenuItem_Click(sender As Object, e As EventArgs) Handles _saveAsMenuItem.Click
    28. Using sfd As New SaveFileDialog()
    29. Dim formats() As FileFormatDescription = ExecutionContext.GetFilter(SaveOperation.SaveMain)
    30. sfd.Filter = String.Join("|", formats.Select(Function(p)p.ToString())
    31. If sfd.ShowDialog() = DialogResult.OK Then
    32. ExecutionContext.Save(sfd.FileName, formats(sfd.FilterIndex), myData, SaveOperation.SaveMain)
    33. End If
    34. End Using
    35. End Sub
    36. End Class
    37. Public Class SomeExecutionContext
    38. Public Shared ReadOnly [Default] As New ExecutionContext()
    39. 'da es keine abstrakten Member gibt, wird statt MustInherit einfach ein geschützter Konstruktor verwendet
    40. Protected Sub New()
    41. End Sub
    42. Public Overridable ReadOnly Property CanSave As Boolean
    43. Get
    44. Return False
    45. End Get
    46. End Property
    47. Public Overridable Function GetFilter(operation As SaveOperation) As FileFormatDescription()
    48. Throw New NotSupportedException()
    49. End Function
    50. Public Overridable Sub Save(fileName As String, format As FileFormatDescription, data As Object, operation As SaveOperation)
    51. Throw New NotSupportedException()
    52. End Sub
    53. End Class
    54. Public Enum SaveOperation
    55. SaveMain = 0
    56. ExportMain
    57. 'verschiedene Speicheroperationen, oder so, ist ja nur ein Beispiel, wie sowas aussehen könnte, daran bist du natürlich nicht gebunden
    58. End Enum
    59. Public Class FileFormatDescription
    60. Public Shared Readonly Any As New FileFormatDescription("*", "Any file type")
    61. Public Property Wildcard As String
    62. Public Property Description As String
    63. Public Sub New(description As String, wildcard As String)
    64. If description.Contains("|"c) OrElse wildcard.Contains("|"c) Then
    65. Throw New ArgumentException("Pipe char (""|"") is not supported in filter constraint description and wildcard.)
    66. End If
    67. Me.Wildcard = wildcard
    68. Me.Description = description
    69. End Sub
    70. Public Sub New(description As String, ParamArray wildcards() As String)
    71. Me.New(String.Join(";", wildcards))
    72. End Sub
    73. Public Overrides Function ToString() As String
    74. Return Description & "|" & Wildcard
    75. End Function
    76. End Class

    Die Klasse übernimmt eben das Verhalten, das mehr oder weniger abstrakt definiert wurde, die Form lediglich die Darstellung.

    Btw: keine Garantie auf Richtigkeit des Codes.

    Gruß
    ~blaze~

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „~blaze~“ ()

    Sagen wir so, eine richtige Formatierung würde helfen (dass ich das einem Mod mal sagen würde 8o ;) ), ohne Einrückungen ist es noch schwerer.
    Und dann sind die Benamungen für mich nichtssagend, so dass ich ständig durcheinander komme.

    EDIT: Eigentlich ist es nur der Name "ExecutionContext", die anderen leiten sich ja davon ab. Was soll der Name bedeuten?