Letzte Useraktion rückgängig machen - Umsetzungsidee gesucht

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

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Letzte Useraktion rückgängig machen - Umsetzungsidee gesucht

    Moin Leute,

    leider bin ich gedanklich in einer Sackgasse gelandet, vielleicht könnt Ihr helfen? Dankeschön fürs Lesen!

    Folgendes Beispiel:

    Eine Form und eine ListBox mit dem Inhalt (Flussdiagramm Stufe 1):

    Autos
    Motoräder

    User klickt Auto -> der Inhalt der ListBox änder sich wie folgt (Stufe 2):

    VW
    BMW
    Skoda

    User klickt VW -> der Inahlt der ListBox änder sich wieder wie folgt (Stufe 3):

    T5
    T6
    Golf4
    Passat3


    Wie sollte man die Idee eines mach die Letzte Wahl/Klick rückgängig Button aussehen?
    (User wollte z.B. BMW statt VW klicken oder User wollte Motorrad statt Autos wählen)
    codewars.com Rank: 4 kyu
    In der Theorie besitzt jeder Eintrag einen oder keinen übergeordneten Eintrag. Speicherst du dir den aktuell ausgewählten Eintrag (z.B. VW), dann kannst du via übergeordneten Eintrag des gespeicherten Eintrags (VW => Autos) wieder alle Eintäge laden, die dem Eintrag Autos untergeordnet sind. Somit könntest du einen "Zurück"/"Ebene höher" Button implementieren.

    Edit: Denk an eine Baumstruktur:
    MESS WITH THE BEST, DIE LIKE THE REST! :evil:
    n'paar Links: DNS Tools, Steal WA DB, Droidsheep...
    Ich hab hab halt "Angst" vor den ganzen if Schleifen etc. es reicht ja schon eine Richtung und dann dasselbe noch mal rückwärts.

    Jetzt denk ich gerade pseudo Code:

    UserInput ={"Stufe1" = "Auto", "Stufe2" = "VW", "Stufe3"="T5"}

    User drückt ZurückButton -> letzte Key:Value Paar in dem AntwortSammelString löschen -> UserInput ={"Stufe1" = "Auto", "Stufe2" = "VW"} und diese Info nutzen um eine "neue Auswahl" bis zu dieser Stelle automatisch zu erzeugen.

    Also erzeuge einen neuen AntwortSammelString (starte Methode Zurueck(UserInput)) und starte die Baustruktur von Vorne nur diesmal entscheide automatisch anhand des alten AntwortStrings welcher Zweig genommen werden soll und stopp eine Stufe früher.

    Ich hoffe mal das das richtig ist was ich mir ausdenke...

    Danke für den Gedankenanstoß
    codewars.com Rank: 4 kyu
    Hi,

    das lässt sich in diesem Fall recht elegant mit einem Stack lösen. Erst mal der Code:

    VB.NET-Quellcode

    1. Imports System.Collections.Generic
    2. Public Class Form1
    3. Private topLevelEntry As New Entry()
    4. Private states As New Stack(Of Entry)
    5. Public Sub New()
    6. InitializeComponent()
    7. Dim cars = New Entry()
    8. cars.Items.AddRange({"BMW", "Audi", "VW"})
    9. Dim bmws = New Entry()
    10. bmws.Items.AddRange({"320i", "330i", "850csi", "730d"})
    11. cars.Entries.Add(bmws)
    12. Dim audis = New Entry()
    13. audis.Items.AddRange({"A3", "A4", "RS4"})
    14. cars.Entries.Add(audis)
    15. Dim vws = New Entry()
    16. vws.Items.AddRange({"Golf", "Passat", "Käfer"})
    17. cars.Entries.Add(vws)
    18. Dim bikes = New Entry()
    19. bikes.Items.AddRange({"Harley", "BMW", "Duccati"})
    20. Dim harleys = New Entry()
    21. harleys.Items.AddRange({"Harley1", "Harley2", "Harley3"})
    22. bikes.Entries.Add(harleys)
    23. Dim bmwBikes = New Entry()
    24. bmwBikes.Items.AddRange({"BMW1", "BMW2"})
    25. bikes.Entries.Add(bmwBikes)
    26. Dim duccaties = New Entry()
    27. duccaties.Items.AddRange({"Duccati1", "Duccati2", "Duccati3", "Duccati4"})
    28. bikes.Entries.Add(duccaties)
    29. topLevelEntry.Items.AddRange(New String() {"Autos", "Motorräder"})
    30. topLevelEntry.Entries.AddRange({cars, bikes})
    31. states.Push(topLevelEntry)
    32. ListBox1.DataSource = states.Peek().Items
    33. End Sub
    34. Private Sub ListBox1_Click(sender As Object, e As EventArgs) Handles ListBox1.Click
    35. Dim index = Me.ListBox1.SelectedIndex
    36. If index > -1 Then
    37. Dim entry = states.Peek()
    38. If (entry.Entries.Count > 0) Then
    39. states.Push(states.Peek().Entries(index))
    40. ListBox1.DataSource = states.Peek().Items
    41. End If
    42. End If
    43. End Sub
    44. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    45. If states.Count > 1 Then
    46. states.Pop()
    47. ListBox1.DataSource = states.Peek().Items
    48. End If
    49. End Sub
    50. End Class
    51. Public Class Entry
    52. Public Items As New List(Of String)
    53. Public Entries As New List(Of Entry)
    54. End Class


    Als erstes wird ein topLevelEntry (Autos, Motörräder) erzeugt. Jeder Entry in diesem topLevelEntry bekommt wiederrum Entries (Autos => BMW, Audi...., Motorräder => Harley, Duccati....). Und jedem dieser Entries werden nun die Modelle zugeordnet.

    Wird die ListBox geclicked, wird der gewählte Eintrag auf den Stack gepushed. Es wird über den Index festgelegt, welcher Eintrag gewählt wurde. Der letzte Eintrag auf dem Stack wird nun angezeigt. Clickt man den Zurück-Button (hier button1), so wird das erste Item vom Stack genommen und verworfen und das darunterliegende angezeigt....

    Das ist nur auf die Schnelle zusammengezimmert und soll auch nur das Prinzip verdeutlichen. Keine Garantie auf Richtigkeit und Vollständigkeit.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    Prinzipiell ist hier der Commadn-Pattern gefordert, und zwar in der verschärften Version, wo jedes Command aus einer Do und einer UnDo - Action besteht.
    Und jegliche Aktion darf nur über diese Commands laufen.
    Die Commands gehören in eine History-List (nicht Stack) - dann kann man den Do/UnDo/ReDo-Pattern implementieren.
    CodeSample habich vor langem mal auf myCSharp gemacht - müsste ich suchen.
    @FormFollowsFunction Leider ist das ein hohler Vogel, da wurden leider alle Anhänge geleert, auch im verlinkten Post.
    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!
    @FormFollowsFunction Sorry, ich hab sie in nem neuen Tab geöffnet, da stand ne leere XML-Hülse.
    Eben hab ich es noch mal gemacht, da funktioniert es.
    Unklar. Freitag der 13. war gestern. 8|
    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!
    Erstmal Danke an alle Poster ... :)

    @SpaceyX Danke für den Aufwand mir so im Detail zu helfen. @ErfindesRades Wie immer unglaublich was Du für die Community schon gemacht hast und machst Danke
    Es schein wie immer zu sein, ich muss mich erstmal mit mir neuen Sachen beschäftigen, bis ich Eure Vorschläge umsetzen kann. Für den Moment ist mir SpaceyX Ansatz näher an dem, wie ich es selber versucht hätte. Wusste aber nicht das es die Stack() Methode gibt.
    Die Richtung ist erstmal klar ... also ran an die Umsetzung ;)
    codewars.com Rank: 4 kyu
    @SpaceyX So ganz klar durchdenken kann ich die Lösung immer noch nicht. Aber der Nebel lichtet sicher immer mehr. Am ehesten musste ich an Escher Bilder denken (endlose Treppen etc.).

    Zur Sache: Ich hab Dein Beispiel im Fall Auto->BMW mal um eine Detailstufe vertieft "Leistung" (140 PS, 220 PS).

    Wenn man die Baumstruktur noch weiter verästeln würde, würde der Code ja doch recht lang (nicht schwer aber eben viele Zeilen). Sollte ich mir die Lösung von @ErfinderDesRades doch noch genauer ansehen oder wächst der Code da auch mit der Anzahl der Verästelungen stark an? Ich bin leider nicht erfahren genug, um schnell zu sehen, ob es sich lohn die Zeit da zu investieren.

    Hier mal meine "Erweiterung" (die Namen der Klassen etc. hab ich auch geändert, um für mich selber besser klar zu kommen).
    Die Form besitzt jetzt 1xButton 2xListBox 1xRichTextBox. Die Extra Anzeigen hab ich mir noch reingesetzt, um besser zu sehen was bei jedem Schritt passiert.

    Tausend Dank nochmal für deinen Vorschlag!

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private topLevelEntry As New EntryClass()
    3. Private StackStufe As New Stack(Of EntryClass)
    4. Public Sub New()
    5. InitializeComponent()
    6. Dim cars = New EntryClass()
    7. cars.propLstStringItems.AddRange({"BMW", "Audi", "VW"})
    8. ' CARS
    9. Dim bmws = New EntryClass()
    10. bmws.propLstStringItems.AddRange({"320i", "330i", "850csi", "730d"})
    11. cars.propLstEntrysObj.Add(bmws)
    12. '"nogood" Testerweiterung Anfang
    13. Dim leistung320 = New EntryClass()
    14. leistung320.propLstStringItems.AddRange({"320 PS", "220 PS"})
    15. bmws.propLstEntrysObj.Add(leistung320)
    16. Dim leistung330 = New EntryClass()
    17. leistung330.propLstStringItems.AddRange({"330 PS", "220 PS"})
    18. bmws.propLstEntrysObj.Add(leistung330)
    19. Dim leistung850 = New EntryClass()
    20. leistung850.propLstStringItems.AddRange({"850 PS", "220 PS"})
    21. bmws.propLstEntrysObj.Add(leistung850)
    22. Dim leistung730 = New EntryClass()
    23. leistung730.propLstStringItems.AddRange({"730 PS", "220 PS"})
    24. bmws.propLstEntrysObj.Add(leistung730)
    25. '"nogood" Testerweiterung Ende
    26. Dim audis = New EntryClass()
    27. audis.propLstStringItems.AddRange({"A3", "A4", "RS4"})
    28. cars.propLstEntrysObj.Add(audis)
    29. Dim vws = New EntryClass()
    30. vws.propLstStringItems.AddRange({"Golf", "Passat", "Käfer"})
    31. cars.propLstEntrysObj.Add(vws)
    32. Dim bikes = New EntryClass()
    33. bikes.propLstStringItems.AddRange({"Harley", "BMW", "Duccati"})
    34. ' BIKES
    35. Dim harleys = New EntryClass()
    36. harleys.propLstStringItems.AddRange({"Harley1", "Harley2", "Harley3"})
    37. bikes.propLstEntrysObj.Add(harleys)
    38. Dim bmwBikes = New EntryClass()
    39. bmwBikes.propLstStringItems.AddRange({"BMW1", "BMW2"})
    40. bikes.propLstEntrysObj.Add(bmwBikes)
    41. Dim duccaties = New EntryClass()
    42. duccaties.propLstStringItems.AddRange({"Duccati1", "Duccati2", "Duccati3", "Duccati4"})
    43. bikes.propLstEntrysObj.Add(duccaties)
    44. topLevelEntry.propLstStringItems.AddRange(New String() {"Autos", "Motorräder"})
    45. topLevelEntry.propLstEntrysObj.AddRange({cars, bikes})
    46. StackStufe.Push(topLevelEntry)
    47. ListBox1.DataSource = StackStufe.Peek().propLstStringItems
    48. 'EGO
    49. Aktualisieren()
    50. End Sub
    51. Private Sub ListBox1_Click(sender As Object, e As EventArgs) Handles ListBox1.Click
    52. Dim index = Me.ListBox1.SelectedIndex
    53. 'EGO
    54. RichTextBox1.Text += "Index selected: " + index.ToString + " : " + Me.ListBox1.SelectedItem.ToString + vbNewLine
    55. ListBox2.Items.Add(Me.ListBox1.SelectedItem.ToString)
    56. If index > -1 Then
    57. Dim entryClassobj = StackStufe.Peek()
    58. If (entryClassobj.propLstEntrysObj.Count > 0) Then
    59. StackStufe.Push(StackStufe.Peek().propLstEntrysObj(index))
    60. ListBox1.DataSource = StackStufe.Peek().propLstStringItems
    61. End If
    62. End If
    63. 'EGO
    64. Aktualisieren()
    65. End Sub
    66. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    67. If StackStufe.Count > 1 Then
    68. StackStufe.Pop()
    69. ListBox1.DataSource = StackStufe.Peek().propLstStringItems
    70. 'EGO
    71. Aktualisieren()
    72. End If
    73. If ListBox2.Items.Count > 0 Then
    74. ListBox2.Items.RemoveAt(ListBox2.Items.Count - 1)
    75. End If
    76. End Sub
    77. Public Class EntryClass
    78. Public propLstStringItems As New List(Of String)
    79. Public propLstEntrysObj As New List(Of EntryClass)
    80. End Class
    81. Private Sub Aktualisieren()
    82. 'EGO
    83. Dim counter As Integer = 0
    84. RichTextBox1.Text += "==========================================" + vbNewLine
    85. RichTextBox1.Text += "StackStufe: " + StackStufe.Count.ToString + vbNewLine
    86. For Each obj In StackStufe
    87. RichTextBox1.Text += "EntryClass-> List Items Einträge: "
    88. For Each eintrag In obj.propLstStringItems
    89. RichTextBox1.Text += eintrag + " // "
    90. Next
    91. counter = obj.propLstEntrysObj.Count
    92. RichTextBox1.Text += vbNewLine + "Anzahl List(Of EntryClass): " + counter.ToString + vbNewLine + "--------------------------------" + vbNewLine
    93. Next
    94. RichTextBox1.Text += vbNewLine
    95. End Sub
    96. End Class


    Gibt es zu meiner Erweiterung "Leistung PS" noch was zu sagen (außer das die Benamung mau ist :) ).
    codewars.com Rank: 4 kyu