Code für mehrere PictureBox-Eventhandler zusammenfassen

  • C#
  • .NET (FX) 4.5–4.8

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

    Code für mehrere PictureBox-Eventhandler zusammenfassen

    Hallo,

    ich habe einst in VB.Net dies gekonnt:


    VB.NET-Quellcode

    1. Private Sub PictureBoxes_DoubleClick(sender As Object, e As EventArgs) Handles PictureBox1.DoubleClick,
    2. PictureBox2.DoubleClick,
    3. PictureBox3.DoubleClick,
    4. PictureBox4.DoubleClick,
    5. PictureBox5.DoubleClick,
    6. PictureBox6.DoubleClick
    7. Dim pb As PictureBox = DirectCast(sender, PictureBox)
    8. Dim n As Integer = CInt(pb.Tag)
    9. If NeueListeBitmaps?.Count > n Then
    10. NeueListeBitmaps.RemoveAt(n)
    11. Liste_mit_Pfaden.RemoveAt(n)
    12. pb.Image.Dispose()
    13. pb.Image = Nothing
    14. Something_has_actually_changed = True
    15. End If
    16. End Sub


    Nun möchte ich das Ganze in C# haben. Ich bekomme das Zusammenfassen der Handles nicht hin. Hier steht 6× derselbe Code. Könntet ihr mir bitte helfen?

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Drawing;
    4. using System.Windows.Forms;
    5. namespace IA
    6. {
    7. public partial class FormEdit : Form
    8. {
    9. public FormEdit()
    10. {
    11. InitializeComponent();
    12. }
    13. private readonly List<System.Drawing.Bitmap> ListOfPhotos = new List<System.Drawing.Bitmap>();
    14. private readonly List<string> ListOfPathsOfThePhotos = new List<string>();
    15. private void PictureBox1_DoubleClick(object sender, EventArgs e)
    16. {
    17. PictureBox pbox = (PictureBox)sender;
    18. int n = System.Convert.ToInt32(pbox.Tag);
    19. if (ListOfPhotos?.Count > n)
    20. {
    21. ListOfPhotos.RemoveAt(n);
    22. ListOfPathsOfThePhotos.RemoveAt(n);
    23. pbox.Image.Dispose();
    24. pbox.Image = null;
    25. }
    26. }
    27. private void PictureBox2_DoubleClick(object sender, EventArgs e)
    28. {
    29. PictureBox pbox = (PictureBox)sender;
    30. int n = System.Convert.ToInt32(pbox.Tag);
    31. if (ListOfPhotos?.Count > n)
    32. {
    33. ListOfPhotos.RemoveAt(n);
    34. ListOfPathsOfThePhotos.RemoveAt(n);
    35. pbox.Image.Dispose();
    36. pbox.Image = null;
    37. }
    38. }
    39. private void PictureBox3_DoubleClick(object sender, EventArgs e)
    40. {
    41. PictureBox pbox = (PictureBox)sender;
    42. int n = System.Convert.ToInt32(pbox.Tag);
    43. if (ListOfPhotos?.Count > n)
    44. {
    45. ListOfPhotos.RemoveAt(n);
    46. ListOfPathsOfThePhotos.RemoveAt(n);
    47. pbox.Image.Dispose();
    48. pbox.Image = null;
    49. }
    50. }
    51. private void PictureBox4_DoubleClick(object sender, EventArgs e)
    52. {
    53. PictureBox pbox = (PictureBox)sender;
    54. int n = System.Convert.ToInt32(pbox.Tag);
    55. if (ListOfPhotos?.Count > n)
    56. {
    57. ListOfPhotos.RemoveAt(n);
    58. ListOfPathsOfThePhotos.RemoveAt(n);
    59. pbox.Image.Dispose();
    60. pbox.Image = null;
    61. }
    62. }
    63. private void PictureBox5_DoubleClick(object sender, EventArgs e)
    64. {
    65. PictureBox pbox = (PictureBox)sender;
    66. int n = System.Convert.ToInt32(pbox.Tag);
    67. if (ListOfPhotos?.Count > n)
    68. {
    69. ListOfPhotos.RemoveAt(n);
    70. ListOfPathsOfThePhotos.RemoveAt(n);
    71. pbox.Image.Dispose();
    72. pbox.Image = null;
    73. }
    74. }
    75. private void PictureBox6_DoubleClick(object sender, EventArgs e)
    76. {
    77. PictureBox pbox = (PictureBox)sender;
    78. int n = System.Convert.ToInt32(pbox.Tag);
    79. if (ListOfPhotos?.Count > n)
    80. {
    81. ListOfPhotos.RemoveAt(n);
    82. ListOfPathsOfThePhotos.RemoveAt(n);
    83. pbox.Image.Dispose();
    84. pbox.Image = null;
    85. }
    86. }
    87. }
    88. }
    Das läuft doch glaub ich in der .Designer.cs mit der Syntax Control.Event += DeinEventHandler. Einfach mal n Button erstellen, Doppelklick drauf und dann in der Designer.cs nachschauen.
    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.
    Ich habe mir in der normalen .cs-Datei eine Prozedur erstellt

    C#-Quellcode

    1. private void PictureBoxes_DoubleClick(object sender, EventArgs e)
    2. {
    3. }
    .
    In der Designer.cs habe ich diese Zeile geschrieben:

    this.PictureBoxes_DoubleClick += new System.EventHandler(this.PictureBox1_DoubleClick);

    Das ergibt eine Fehlermeldung.

    Bartosz schrieb:

    C#-Quellcode

    1. this.PictureBoxes_DoubleClick += new System.EventHandler(this.PictureBox1_DoubleClick);
    Mach das im Designer und sieh Dir den Sesign-Code an.
    Anders herum:

    C#-Quellcode

    1. this.PictureBox1.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    2. this.PictureBox2.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    3. this.PictureBox3.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    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!
    na toll, ich und C# und Events xD

    C#-Quellcode

    1. private void PictureBoxes_DoubleClick(object sender, EventArgs e)
    2. {
    3. PictureBox pbox = (PictureBox)sender;
    4. int n = System.Convert.ToInt32(pbox.Tag);
    5. if (ListOfPhotos?.Count > n)
    6. {
    7. ListOfPhotos.RemoveAt(n);
    8. ListOfPathsOfThePhotos.RemoveAt(n);
    9. pbox.Image.Dispose();
    10. pbox.Image = null;
    11. A_property_has_been_changed = true;
    12. }
    13. }


    in .Designer.cs

    C#-Quellcode

    1. this.PictureBox1.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    2. this.PictureBox2.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    3. this.PictureBox3.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    4. this.PictureBox4.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    5. this.PictureBox5.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);
    6. this.PictureBox6.DoubleClick += new System.EventHandler(this.PictureBoxes_DoubleClick);


    Gut, ich danke euch :)

    Bartosz schrieb:

    C#-Quellcode

    1. PictureBox pbox = (PictureBox)sender;
    Ich bau da immer noch eine Sicherheit ein:

    C#-Quellcode

    1. PictureBox pbox = sender as PictureBox;
    2. if (pbox == null) return;
    ====
    Beachte den Unterschied zwischen

    C#-Quellcode

    1. pbox = (PictureBox)sender
    2. // und
    3. pbox = sender as PictureBox;

    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 habe hier gelesen:
    Der "as"-Operator konvertiert das Ergebnis eines Ausdrucks explizit in einen bestimmten Referenz- oder nullbaren Werttyp. Wenn die Umwandlung nicht möglich ist, gibt der "as"-Operator null zurück. Im Gegensatz zu einem Cast-Ausdruck löst der "as"-Operator nie eine Ausnahme aus.


    Danke dir dafür und danke für den Hinweis mit der NULL-Prüfung.

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

    Bartosz schrieb:

    Danke dir dafür und danke für den Hinweis mit der NULL-Prüfung.
    Ich sehe keinen Sinn darin. Bzw es besteht die Gefahr, dass Unsinn-Code übersehen wird.
    Bleib beim (cast), der wirft eine Exception, wenn sender keine Picbox ist.
    Mit as entfällt die Exception, und musst extra in einem Zusatz-Schritt drauf prüfen.
    Wo du beim (cast) doch direkt drauf gestossen würdest.

    Bei

    C#-Quellcode

    1. PictureBox pbox = sender as PictureBox;
    2. if (pbox == null) return;
    kann auch ein Button seinen DoubleClick senden - was ja Quatsch wäre. Und würde darauf hindeuten, dass des Buttons DoubleClick irgendwoanders nicht hingeht.
    Deshalb ist die InvalidCast-Exception an der Stelle genau richtig, und die Konstruktion mit as ist bischen mehr Code und bringt Verwässerung der Typ-Überprüfung.

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

    ErfinderDesRades schrieb:

    was ja Quatsch wäre.
    Im Prinzip ja, aber das ist ein besserer Code als ohne.
    Und wenn man sich diesen Konstrukt angewöhnt, ist man stets auf der richtigen Seite.
    @ErfinderDesRades Wenn wir Exceptions vermeiden wollen, ist der as-Operator die Lösung, wenn es da mal versehentlich knallt.
    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!

    RodFromGermany schrieb:

    Und wenn man sich diesen Konstrukt angewöhnt, ist man stets auf der richtigen Seite.
    @ErfinderDesRades Wenn wir Exceptions vermeiden wollen...
    Wie ich in der TryCatch-Diskussion ja immer ausführe: Exceptions sind unsere Freunde - wir wollen sie keinesfalls vermeiden.
    Wir sind dankbar dafür, dass sie uns die Programmier-Fehler melden, die wir gemacht haben, und die wir dank der Exceptions beheben können - anders würden die ja im Programm verbleiben.
    Etwa dass ein anderes Control sein DoubleClick an PictureBoxes_DoubleClick sendet, ist nicht in Ordnung, und ist zu korrigieren.
    Dank deines "sicheren Codes" bliebe die Korrektur aber aus, und der Programmier-Fehler drinne - es ist also die unsichere Seite.

    So etwas nicht angewöhnen! - sagich.

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

    ErfinderDesRades schrieb:

    Etwa dass ein anderes Control sein DoubleClick an PictureBoxes_DoubleClick sendet, ist nicht in Ordnung, und ist zu korrigieren.
    Jein. ;)
    Bei der nächsten PictureBox mit diesem Eventhandler ist das in Ordnung.
    Bei einem Label-DoubleClick z.B. würde nix passieren.
    In meinem Code steht dann ein Debugger.Break() in einem DEBUG-Compilerschalter (=> Bedingter Haltepunkt), der mir genau sagt, dass und wo in meinem Programm Handlungsbedarf ist.
    Früher hatte ich da ein Debug.Assert(...) stehen, das wird aber nur im GUI-Thread geworfen.
    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!
    @ErfinderDesRades

    RodFromGermany schrieb:

    Bei einem Label-DoubleClick z.B. würde nix passieren.
    ... in der selben Prozedur ...
    Bei Dir käme bei jedem einzelnen Aufruf eine Exception ohne die Möglichkeit, das zu umgehen..
    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!
    Hallo,
    auch wenn das Thema eigentlich abgeschlossen ist, habe ich noch ein paar Vorschläge für @Bartosz:
    Mit neuen Versionen von C# ist das Pattern-Matching gekommen bzw. weiter ausgebaut und ist ein schönes Werkzeug.

    C#-Quellcode

    1. private void PictureBoxes_DoubleClick(object sender, EventArgs e)
    2. {
    3. if ((sender is PictureBox pbox) && ((pbox.Tag is int n) && (ListOfPhotos?.Count > n)))
    4. {
    5. ListOfPhotos.RemoveAt(n);
    6. ListOfPathsOfThePhotos.RemoveAt(n);
    7. pbox.Image.Dispose();
    8. A_property_has_been_changed = true;
    9. }
    10. }

    Ich bin kein Freund davon, wenn eine Forms-Anwendung den Benutzer mit einer Exception verabschiedet. Da gehört eine ordentliche Fehlermeldung für den Benutzer hin und die Exception ins Eventlog geschrieben (oder mit einem anderen Logging-Mechanismus verarbeitet; falls man Exceptions denn verwenden möchte). Das Pattern-Matching wirft ebenfalls keine Exception. Heißt, mach nur etwas, wenn es eine PixtureBox ist. Da die Eigenschaft Tag ein Object ist, hoffe ich, du schreibst dort auch einen Integer rein, wenn du einen Integer brauchst. Daher aus meiner Sicht völlig unnötig System.Convert zu verwenden. (Es sei denn, du setzt Tag durch den Windows-Forms-Designer. Der lässt nur Text zu :D ).
    Du brauchst Image nicht explizit auf null zu setzen, das macht Dispose für dich. Daher diese Zuweisung entfernt.
    @ISliceUrPanties Danke für den modernen Vorschlag! :)

    Zum Thema Exceptions: Ich bin auch ein Freund davon, dass ich als Entwickler mitbekomme, dass ein Fehler geschieht; denn ich teste ja auch alles Mögliche ab und werde dann auf den Fehler durch die Exception aufmerksam. Ich würde es nicht gut finden, wenn nun ein Label-Doppelklick diesen Code ausführt. Aber das passiert ja auch nicht, habt ihr gesagt. Der Endbenutzer soll nicht das Erlebnis haben, dass eine Fehlermeldung kommt und er das Programm ausschalten muss.

    hoffe ich, du schreibst dort auch einen Integer rein
    Ja, im Designer haben die Pictureboxen jeweils einen Integer, aufsteigend.

    Daher aus meiner Sicht völlig unnötig System.Convert zu verwenden.
    Stammt noch vom Telerik-Converter.

    Bartosz schrieb:

    Ich würde es nicht gut finden, wenn nun ein Label-Doppelklick diesen Code ausführt.
    Wenn bei einer GUI mit PictureBoxen und Labels übereall (imk o.g. Sinne) derselbe Code ausgeführt werden soll, ist das schon sinnvoll.
    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!
    Um das Thema Pattern Matching noch ein wenig auf die Spitze zu treiben, wenn dein Event-Handler wirklich mit mehreren Typen umgehen können soll, kann man das z.B. so lösen

    C#-Quellcode

    1. ​void DoubleClickHandler(object sender, EventArgs e)
    2. {
    3. A_property_has_been_changed = sender switch
    4. {
    5. PictureBox { Tag: int n } pb => FunctionWithPictureBoxImage(pb.Image, n),
    6. Label l => FunctionWithLabel(l),
    7. _ => LogError()
    8. };
    9. }
    10. bool FunctionWithPictureBoxImage(Image image, int index)
    11. {
    12. if (ListOfPhotos?.Count <= index)
    13. {
    14. return false;
    15. }
    16. ListOfPhotos.RemoveAt(index);
    17. ListOfPathsOfThePhotos.RemoveAt(index);
    18. image.Dispose();
    19. return true;
    20. }
    21. bool FunctionWithLabel(Label l)
    22. {
    23. // ... Do something
    24. return false;
    25. }
    26. bool LogError()
    27. {
    28. // ... Do something
    29. return false;
    30. }


    Interessant ist hier, dass die Eigenschaft Tag wieder in die Variable n gematched wird, wenn es ein int ist (Property-Matching). Sollte also in Tag "5" stehen, gibt es kein "Match" und er würde in den default-Zweig gehen und LogError aufrufen. In der Doku findet man noch viel mehr Möglichkeiten.

    ISliceUrPanties schrieb:

    A_property_has_been_changed = sender switch
    Immerhin hat er gemerkt, dass dieses Muster in FW 4.8 nicht nur nicht vorhanden ist, sondern er weiß auch, ab wann es zu finden ist:
    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!

    ISliceUrPanties schrieb:

    Ich bin kein Freund davon, wenn eine Forms-Anwendung den Benutzer mit einer Exception verabschiedet. Da gehört eine ordentliche Fehlermeldung für den Benutzer hin
    ich auch nicht.
    Aber da gehört keine Fehlermeldung hin, sondern der Code ist natürlich so zu schreiben, dass kein Fehler auftritt.
    Ist ja bei derlei Dumm-Fehlern kein Ding der Unmöglichkeit.