UserControls auf TabControl TapPages <> 0 sehen komisch aus

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

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von roepke.

    UserControls auf TabControl TapPages <> 0 sehen komisch aus

    Ich mache hier nochmal einen neuen Thread für das Thema auf.
    In meiner letzten Frage ging das unter, da es grundlegend erst mal um was anderes ging.
    Daher verschiebe ich's mal nach hier.
    Ich habe ein kleines Beispielprojekt erstellt und angehängt.

    In MyDLL befindet sich ein UserControl (MuxControl).
    In MyProject gibt es das MyUserControl, das 3 Instanzen von MuxControl beinhaltet.
    Über das frm_Main können die frm_Sub_1 und frm_Sub_2 geöffnet weden.
    Beide frm_Sub_x besitzen ein TabControl auf dem auf jeweils einer TabPage ein MyUserControl zu finden ist.
    Die beiden MyUserControl sind mittels Event „miteinander in Kontakt“. D.h. wird bei einem MuxControl ein Eintrag <> Disabled ausgewählt, wird das gleiche MuxControl auf dem anderen MyUserControl gesperrt und dort angezeigt, dass dieser „Kanal“ bereits verwendet wird.
    Das funktioniert auch soweit.
    Was nicht funktioniert ist mal wieder die leidige Initialisierung der Controls auf den TabPages <> Index = 0.
    -Erst frm_Sub_1 öffnen
    -Dort auf TabPage.Index = 0 ist das MyUserControl zu finden. Layout sieht aus, wie es aussehen soll.
    -z.B. beim mittleren MuxControl einen Eintrag <> Disabled wählen
    -frm_Sub_2 öffnen
    -Dort auf TabPage.Index = 1 ist das MyUserControl zu finden. Layout sieht NICHT aus, wie es aussehen soll.

    -mittleres MuxControl ist gesperrt
    -z.B. beim oberen MuxControl einen Eintrag <> Disabled wählen
    -alle vorhandenen MyUserControls werden aktualisert, danach stimmt das Layout auch auf frm_Sub_2.

    Ich habe schon jede Menge versucht das zu beheben. Leider bisher ohne Erfolg.
    Dass das TabControl ein bißchen "speziell" ist habe ich inzwischen auch begriffen. Nur fehlt mir eine gute Idee für ein Workaround.
    Dateien
    @roepke Sieh Dir mal die Werte der Properties Margin und Padding an.
    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!
    Tausch mal
    MyUserControl_tp2.uc_Shown() und MuxControl_Init(), also mach:

    VB.NET-Quellcode

    1. Call MyUserControl_tp2.uc_Shown() 'Das ist nötig, damit beim Anlegen des Forms schon andersweitig benutze MuxControls in diesem Form als bereits benutzt angezeigt werden.
    2. Call MuxControl_Init()
    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.
    Ja, ich seh grad. Das alte, leidige Thema TabControl/TabPage: Was nicht sichtbar ist, ist nicht da.
    Mach mal:

    VB.NET-Quellcode

    1. Private Sub MuxControl_Init()
    2. Dim _lst As New List(Of String)
    3. _lst.Clear()
    4. _lst.Add("Disabled")
    5. _lst.Add("Entry1")
    6. _lst.Add("Entry2")
    7. tc.SelectedIndex = 1
    8. MyUserControl_tp2.plstMuxControlEntrys = _lst
    9. tc.SelectedIndex = 0
    10. End Sub
    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.

    roepke schrieb:

    was sollten Margin und Padding damit zu tun haben?
    Ich hatte dieses Problem ebenfalls.
    Sieh Dir diese Werte an insbesondere bei TabPage.
    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!

    VaporiZed schrieb:

    Ja, ich seh grad. Das alte, leidige Thema TabControl/TabPage: Was nicht sichtbar ist, ist nicht da.

    Hat leider auch nichts geholfen.
    Das interessante ist: kommentiere ich

    VB.NET-Quellcode

    1. Call mod_General_MuxControlSelectionChanged()

    im MyUSerControl.vb -> uc_Shown aus, dann sieht das UserControl aus, wie es aussehen soll.
    Es scheint also irgendwie mit dem Abgleich zu tun zu haben, der unmitelbar nach dem Anlegen des UserControl überprüft, ob
    ein gleich indiziertes Control bereits auf einem anderen Form verwendet wird und das neue dann ggf. sperrt.

    Ich hatte dieses Problem ebenfalls.

    Ich habe jetzt ein wenig mit Margin und Padding rumgespielt und mir angesehen. Margin der TabPages ist 4;4;4;4 Padding 6;3 und wenn ich's ändere, ändert sich ggf. das Layout aber das Problem bleibt.

    Zitierfehler korrigiert ~VaporiZed

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

    Ich lad mal selber hoch. Ich habe die Hinweise aus Post#2 und #4 eingebaut.
    Achtung, ich hatte nur .NET-Framework 4.8, daher ggf. wieder runtersetzen.
    Projektmappe öffnen, erst das DLL-Projekt kompilieren, damit die DLL erstellt wird, dann MyProject kompilieren.
    Dann starten, dann SubForm1 öffnen, da ne Auswahl treffen, SubForm1 nicht schließen, SubForm2 öffnen und auf dem TabControl die 2. Seite öffnen.
    btw: Das Programm ist in seiner Grundform etwas instabil gebaut. Wenn man da ne falsche SubForm-Reihenfolge anklickt oder was zuviel schließt, schmiert es ab.
    Bilder
    • Result.png

      14,3 kB, 874×408, 101 mal angesehen
    Dateien
    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.
    Bei mir sind's Post #3 und #5, hat kurz gedauert bis ich's kapiert habe.
    Alles klar, so scheint es zu funktionieren.
    Mein Fehler. Ich hatte #3 probiert und danach #5, aber nicht zusammen. Die Kombi machts.

    VaporiZed schrieb:

    Das Programm ist in seiner Grundform etwas instabil gebaut.

    Danke für die Info, ist mir aber bekannt. Das eigentlich Projekt ist über Jahre gewachsen und extrem umfangreich. Ich habe für hier lediglich schnell was zusammengeklickt um das Problem zu schildern/zeigen. Das ich damit keinen Stabilitätspreis gewinne ist klar. Im eigentlichen Programm ist's nicht so wackelig.
    Aufgrund des Umfangs wird's jetzt auch spaßig alle TabPages und UserControls (und davon gibt es einen Haufen) in Ruhe durchzugehen und überall einen entsprechenden Fix zu machen.
    Ich greife aus aktuellem Anlass dieses Thema noch mal auf.
    Ich habe versucht in der MyUserControl.Load herauszufinden, welches Control denn das Parent des UserControls ist und dabei folgendes festgestellt:
    Mit

    VB.NET-Quellcode

    1. Dim _frm As Form = New frm_Sub_1 / New frm_Sub_2
    2. _frm.Show()
    3. Call InitBindability(_frm)

    Wird MyUserControl.Load unmittelbar mit InitBindability(_frm) ausgeführt. Was soweit ja auch OK ist, schließlich werden dort alle TabPages durchselektiert. Aber das ermittelbare Parent-Control stimmt nur frm_Sub_1, weil es sich dort auf der ersten TabPage befindet. Für frm_Sub_2 wird frm_Sub_2 ermittelt, wobei es in Echt tp 2 ist.
    Jetzt sind zwar beide UserControls initialisiert, dafür ist das ermittelte Parent-Control (zumindest für UserControls <> erste TabPage) falsch . Und das ist Mist.

    Mit

    VB.NET-Quellcode

    1. Dim _frm As Form = New frm_Sub_1 / New frm_Sub_2
    2. Call InitBindability(_frm)
    3. _frm.Show()

    Wird MyUserControl.Load erst ausgeführt, wenn die TabPage auf der es sich befindet vom User erstmalig selektiert wird. D.h. für frm_Sub_1 wird das Parent unmittelbar ermittelt, weil sich das UserControl auf tp 1 befindet. Für frm_Sub_2 wird es erst ermittelt, wenn die tp 2 angeklickt wird.
    Jetzt stimmen zwar die ermittelten Parent-Controls, dafür ist mein UserControl wieder erst initialisiert, wenn die TabPage sichtbar angeklickt wurde. Und das ist Mist.

    Hat jemand eine Lösung, wie ich es hinbekommen kann, dass im UserControl beim frm_Sub_2 MyUserControl.Load OHNE die TabPage aktiv anklicken zu müssen durchlaufen wird UND sich trotzdem das richige Parent-Control ermitteln lässt? Irgendwie stehen sich diese beiden Dinge gegenseitig im Weg.
    Dateien

    roepke schrieb:

    Wird MyUserControl.Load unmittelbar mit InitBindability(_frm) ausgeführt
    Weiß ja nicht, wie Du das meinst, aber »unmittelbar mit« klingt für mich nach gleichzeitig. Tatsächlich kommt aber nach dem Show die Load-Methode dran und nachdem die abgearbeitet ist, ist die InitBindability-Methode erst dran. Falls Du das nicht so siehst: Haltepunkte einbauen und der Abarbeitung zusehen.

    roepke schrieb:

    Aber das ermittelbare Parent-Control stimmt nur frm_Sub_1, weil
    Verstehe ich leider inhaltlich nicht.
    Ich bekomme entweder tp1 als Parent angezeigt oder eben tp2. Wie kommt man zu der Programm-Anzeige frm_Sub_X? Bitte genaue Klickabfolge auflisten.
    Das Programm ist immer noch höchst instabil. Klicke ich zuerst auf den [Klick mich um eine frm_Sub_1 Instanz zu öffnen]-Button, schließe das Fenster und klicke dann auf [Klick mich um eine frm_Sub_2 Instanz zu öffnen], crasht das Programm. Andersrum genauso.
    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.
    Erst mal danke für die Antwort.
    Dass das Programm instabil ist weiß ich. Es handelt sich hierbei um ein Beispiel um mein Problem zu zeigen. Das eigentliche Programm ist über Jahre gewachsen und es wäre mega umständlich den Problemteil" dort rauszunehmen. Daher habe ich mit kleinen Teilen davon was "zusammengebaut".

    Im frm_Main im .zip ist die Reihenfolge

    VB.NET-Quellcode

    1. Dim _frm As Form = New frm_Sub_1/ frm_Sub_1
    2. Call InitBindability(_frm)
    3. _frm.Show()

    Also wie in #10 UNTEN beschrieben, InitBindability() VOR .Show() ausgeführt. Dadurch wird das jeweilige UserControl Parent richtig ermittelt. Aber, sofern sich das UserControl NICHT auf der ersten TabPage befindet, wird UserControl.Load() erst ausgeführt, wenn die zugehörige TabPage erstmalig selektiert wird. D.h. ich habe wieder/noch immer das leidige Thema, dass das UserControl erst initialisiert wird, wenn der Nutzer es explizit sehen will. Will er das nicht, bleibt es UNinitialisiert, weil dessen .Load() nie ausgeführt wird.
    Jetzt tausche mal InitBindability() und .Show(), wie in #10 OBEN beschrieben (daher ist das im frm_Main auskommentiert, sorry hatte ich nicht ganz klar ausgedrückt, mein Versäumnis). Dadurch wird InitBindability() NACH .Show() ausgeführt. Jetzt wird bei allen UserControl, egal auf welcher TabPage es sich befindet .Load() unmittelbar ausgeführt, also noch BEVOR der Nutzer überhaupt die Möglichkeit erhält eine TabPage zu wechseln.
    Dumm ist jetzt nur, dass für das UserControl in frm_Sub_2 als Parent dabei eben nicht tp 2, sondern das frm_Sub_2 ermittelt wird.
    Ich stecke also insofern in der Zwickmühle, als dass ich entweder ein evtl. niemals initialisiertes UserControl habe (1. Fall) oder ein falsches Parent erkannt wird (2. Fall). Ich muss mich also zwischen Pest und Cholera entscheiden und suche nach einer Heilung, damit beides passt. Also jedes UserControl egal auf welcher TabPage in jedem Fall .Load() ausführt UND das richtige Parent ermittelt wird.
    Da bei mir immer nur eine TabPage mit Inhalt angezeigt wird, weiß ich nicht, ob mein Vorschlag irgendwas bringt:
    Im UserControl

    VB.NET-Quellcode

    1. Private Sub LoadThisControl_Load(sender As Object, e As EventArgs) Handles Me.Load
    2. AddHandler mod_General.evt_MuxControlSelectionChanged, AddressOf CheckIfMuxControlAlreadyUsedByOtherModule
    3. Console.WriteLine("[MyUserControl_Local.Load] ausgeführt")
    4. End Sub
    5. Friend Sub uc_Shown()
    6. sParentFORMName = Parent.Name
    7. lbl_Info.Text = Parent.Name
    8. Call mod_General_MuxControlSelectionChanged()
    9. End Sub

    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.
    OK, ich habe mich jetzt noch mal etwas mit der „Problematik“ beschäftigt und komme zu folgendem Schluss:
    Wird frm_Sub_2 über frm_Main erstellt, muss in jedem Fall nach dem Erstellen der Forminstanz _frm.Show() stehen und erst dann InitBindability() aufgerufen werden.
    Dadurch wird frm_Sub_2.Load() ausgeführt, in welchem MyUserControl_tp2.uc_Shown() aufgerufen wird. In .uc_Shown() kann ich korrekt die TabPage als Parent erkennen. Beim Ausführen von InitBindability() wird uc.Load() ausgeführt (halt erst nachdem uc.Shown() schon lief). Dort wird das Parent dann NICHT als TabPage, sondern als dessen Form erkannt. Soweit, so doof. Also nutze ich die Erkennung in uc.Shown() und nicht in uc.Load(), wie von @VaporiZed vorgeschlagen.
    Jetzt kommt’s aber: nutze ich in frm_Main anstelle InitBindability() das langsamere InitBindability_Alternative(), dann wird auch in uc.Load() das Parent korrekt als TabPage erkannt. Es hat also mit der Art und Weiße zu tun, wie mittels InitBindability die UserControls auf den TabPages aktiviert werden sollen, obwohl die TabPage als solche nicht angezeigt wird.
    So ganz versteh ich das InitBindability() auch nicht, war mal ein Vorschlag von @ErfinderDesRades in einem anderen Thread.
    Dateien
    probierma

    VB.NET-Quellcode

    1. Private Sub frm_Sub_2_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
    2. Call MyUserControl_tp2.uc_Shown() 'Das ist nötig, damit ....
    3. End Sub
    4. Private Sub frm_Sub_Load(sender As Object, e As EventArgs) Handles Me.Load
    5. Call MuxControl_Init()
    6. End Sub
    evtl. kann das Load-Event dann auch weg - hab nicht alle möglichkeiten durchprobiert.
    Funzt nicht, dadurch bin ich wieder am Anfang: "das UserControl sieht komisch aus".
    Die beiden Aufrufe

    VB.NET-Quellcode

    1. Private Sub frm_Sub_2_Load(sender As Object, e As EventArgs) Handles Me.Load
    2. Call MuxControl_Init()
    3. Call MyUserControl_tp2.uc_Shown() 'Das ist nötig, damit...
    4. End Sub

    müssen in .Load() stehen, dann ist das Problem zumindest behoben.
    Die Sache mit dem nicht richtig erkennen wer das Parent im MyUserContrl.Load() ist auf InitBindability() in frm_Main zurückzuführen.

    Ich hab jetzt auch geklärt, warum in UserControl.Load eben NICHT tp2, sondern frm_Sub_2 erkannt wird.
    Grund ist die Zeile

    VB.NET-Quellcode

    1. parent.Controls.Add(ctl)

    in InitBindability().
    Diese startet im UserControl die .Load(), in der dann das Parent aus der For-Schleife erkennt wird und das ist halt frm_Sub_2 und nicht tp2.
    Ich verstehe ehrlich nicht ganz, was die InitBindablity genau macht.
    Sie fügt dem Parent des TabControls (dem Form) und der TabPage selbst alle Controls nochmals hinzu?
    Oder ist genau das der Bug, das die Controls erst nur deklariert sind und beim ersten sichtbar machen erst definiert werden?
    Aber nur beim hinzufügen zur Form wird die UserControl.Load gestartet.
    Habe probiert die beiden Zeilen

    VB.NET-Quellcode

    1. ' von
    2. 'parent.Controls.Add(ctl)
    3. 'tp.Controls.Add(ctl)
    4. ' nach
    5. tp.Controls.Add(ctl)
    6. parent.Controls.Add(ctl)

    zu tauschen, dann wäre das Parent korrekt die TabPage aber beim hinzufügen zur Tabpage wird die .Load irgendwie nicht ausgeführt.

    Edit: ich habe mir das jetzt noch mal im Debugger angesehen.
    - parent.Controls.Count ist = 0x1 - verstehe ich, es gibt auf dem Form nur das TabControl
    - erreicht die For Each-Schleife TabPage 2 (tp2) ist tp.Controls.Count = 0x1 - verstehe ich, da dort ja das UserControl ist
    - wird nun parent.Controls.Add(ctl) ausgeführt, wird parent.Controls.Count = 0x2 - logisch, es kam ja ein Control dazu
    gleichzeitig wird aber tp.Controls.Count = 0x0 - verstehe ich nicht
    - wird nun tp.Controls.Add(ctl) ausgeführt wird parent.Controls.Count wieder 0x01 und tp.Controls.Count ebenfalls wieder 0x1 - und da endet mein Verständnis, warum ist das so?

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