Initialisierungsproblem mit UserControls auf TabControls

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

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

    Initialisierungsproblem mit UserControls auf TabControls


    Ich habe ein UserControl in einer DLL. Das UserControl besitzt eine Public Property „pbMode“
    Das UserControl wird in seiner .Load initialisiert, dabei wird pbMode = False.
    In meinem Projekt gibt es ein frm_Main. Darüber lässt sich ein frm_Sub öffnen. Auf dem frm_Sub ist ein TabControl.
    Auf der TabPage2 des TabControls befindet sich eine Instanz des UserControls.
    Folgendes Problem: wird die Instanz von

    Quellcode

    1. frm_Setup
    erstellt,

    VB.NET-Quellcode

    1. Dim frm_SubInst As Form
    2. frm_SubInst = New frm_Sub
    3. frm_SubInst.WindowState = FormWindowState.Minimized
    4. frm_SubInst.Show()
    5. For Each _Ctrl As Control In frm_SubInst.Controls
    6. If TypeOf _Ctrl Is TabControl Then
    7. Dim _TabCtrl As TabControl
    8. _TabCtrl = CType(_Ctrl, TabControl)
    9. For _i As Integer = 0 To _TabCtrl.TabPages.Count - 1
    10. _TabCtrl.SelectedIndex = _i
    11. Next
    12. _TabCtrl.SelectedIndex = 0
    13. End If
    14. Next


    geschieht dies über die Designer.vb.
    Darin steht auch die Info zum TabControl, deren TabPages und dem darauf befindlichen UserControl. Dabei wird die Public Property des UserControls pbMode = False gesetzt, weil es so im Designer steht.
    Unmittelbar nach dem Erstellen des frm_Sub, startet das .Load des frm_Setup. Darin wird die Public Property des UserControls pbMode = True gesetzt.
    Ich selektiere alle TabPages des TabControls 1x durch aus folgendem Grund: ich habe festgestellt, dass die auf den TabPage befindlichen (User)Controls NICHT initialisiert wurden, wenn deren zugehörige TabPage nicht mindestens 1x selektiert war.
    Beim durchselektieren kommt auch die TabPage dran auf der sich das UserControl befindet. Dadurch startet im UserControl dessen .Load. Und wie schon eingangs erwähnt, wird dort pbMode = False. Damit ist das True aus frm_Sub.Load hinfällig.
    Ich hatte probiert das Initialisieren der Public Property statt im .Load des frm_Sub in dessen .Shown auszuführen. Nur ist mir absolut nicht verständlich, wann .Shown genau ausgeführt wird.
    Das Problem ist nämlich, dass der Zustand der Public Property auch aus einer Datei kommen kann. D.h. nach dem Laden der frm_Sub Instanz wird sofort der Wert von „pbMode“ aus der Datei gelesen und das UserControl damit gefüttert.
    Und wenn ich nicht wirklich sicher stellen kann, dass .Shown des frm_Sub VOR dem Laden der Datei ausgeführt wird, würde mir das den zuvor geladenen Wert ja auch wieder überschrieben.
    Laut MS ist die Reihenfolge der Events ja .Load, .Activated, .Shown (für das Hauptform). frm_Sub.Activated wird bei mir aber immer nur dann ausgeführt, wenn ich das Form nach dem Laden anklicke. Also scheint sich das für Sub-Forms auch anders zu verhalten.
    Lange Rede kurzer Sinn: ich suche nach einer Möglichkeit das UserControl erst sicher mittels dessen .Load zu initialisieren, bevor entweder das frm_Sub oder die geladenen Datei dies übernimmt.
    @roepke Ich gehe mal davon aus, dass die DLL-Quellen der Projektmappe Deines Programms angehören AndAlso dass Du im Hauptprogramm einen Verweis auf das DLL-Projekt, nicht aber auf die DLL-Datei gesetztr hast.
    Setze in die Quellen überall da, wo Du den Wert auf True setzt, einen Haltepunkt und sieh nach, was beim Laufen passiert.
    Für alle Fälle
    Debuggen, Fehler finden und beseitigen
    Ansonsten poste mal die (abgespeckten) Quellen beider Projekte.
    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!
    zunächstmal zu den Events: ja, das .Activated feuert, wenn das Form den Focus erhält. Erhält es den Focus nicht, feuert es auch nicht.

    Zu deim Initialisierungs-Problem: Offsichtlich darf frm_Sub (oder der Datei-Load - das blicke ich nicht ganz, wattnu) die UserControls erst initialisieren, nachdem du alle Tabs durch-selectiert hast.

    roepke schrieb:

    Und wenn ich nicht wirklich sicher stellen kann, dass .Shown des frm_Sub VOR dem Laden der Datei ausgeführt wird...
    ja, das haste recht - das sollteste sicherstellen können - ist das iwie ein Problem?

    ach - guckma: Dieses doofe Verhalten des TabControls hat mich auch mal um paar graue Haare erweitert. Ich habs mit einer Extension gelöst, bei der nicht wirklich jedes Tab in aller Form aktiviert werden muss:

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Dieser Schwachsinn im Form_Load ausgeführt behebt einen Bug beim DataBinding auf beim Start nicht sichtbaren Tabpages.
    3. ''' </summary>
    4. <Extension()> _
    5. Public Sub InitBindability(tc As TabControl)
    6. Dim parent = tc.FindForm
    7. parent.SuspendLayout()
    8. For Each tp As TabPage In tc.TabPages
    9. tp.SuspendLayout()
    10. For Each ctl In tp.Controls.Cast(Of Control).ToArray
    11. parent.Controls.Add(ctl)
    12. tp.Controls.Add(ctl)
    13. Next
    14. tp.ResumeLayout()
    15. Next
    16. parent.ResumeLayout()
    17. End Sub

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

    @RodFromGermany
    Verweis auf das DLL-Projekt, nicht aber auf die DLL-Datei

    wie mache ich das? Bei mir sieht das so aus:


    @ErfinderDesRades
    vielen Dank für den Codeschnippsel. Ist schicker und flotter als mein "Durchselektieren".
    Habe jetzt einiges propiert und siehe da, das "Durchselektieren" war halt einfach an der faslchen Stelle im Code.
    Ich hatte es direkt nach dem Erstellen der Forminstanz platziert, dabei ist es in Form.Load() einfach besser aufgehoben.
    Da ich aber etliche unterschiedliche Forms erstelle (alle mit TabControl), wollte ich sparsam sein und habe es in frm_Main() platziert und nicht in den jeweilien Form.Load().
    Das ging dann nach hinten los. Habe mir ein paar Infos über die Konsole augeben lassen, jetzt passt die Reihenfolge:

    Spoiler anzeigen

    Quellcode

    1. Bisherige Lösung
    2. Form erstellen
    3. -[MyUserControl_DLL.chk_Mode]=True
    4. -[MyUserControl_Local.chk_Mode]=True
    5. -[MyUserControl_DLL.chk_Mode]=False
    6. -[MyUserControl_DLL.Load] ausgeführt
    7. -[MyUserControl_Local.chk_Mode]=False
    8. -[MyUserControl_Local.Load] ausgeführt
    9. -frm_Main.InitBindability(): 8,9858
    10. Neue Lösung
    11. Form erstellen
    12. -[MyUserControl_DLL.Load] ausgeführt
    13. -[MyUserControl_Local.Load] ausgeführt
    14. -frm_Sub.InitBindability(): 4,8413
    15. -[MyUserControl_DLL.chk_Mode]=True
    16. -[MyUserControl_Local.chk_Mode]=True
    17. mit neuer Lösung: Konfigurationsdatei laden
    18. -[MyUserControl_DLL.Load] ausgeführt -Form/Control erstellen
    19. -[MyUserControl_Local.Load] ausgeführt
    20. -frm_Sub.InitBindability(): 6,5845 -Form.Load()
    21. -[MyUserControl_DLL.chk_Mode]=True
    22. -[MyUserControl_Local.chk_Mode]=True
    23. -[MyUserControl_DLL.chk_Mode]=False -Konfiguration aus Datei laden
    24. -[MyUserControl_Local.chk_Mode]=False

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

    roepke schrieb:

    wie mache ich das?
    Die DLL in den Verweisen löschen.
    Verweis hinzufügen => Projekt => Projektmappe
    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
    Das funktioniert bei mir irgendwie nicht.
    Projektmappen-Explorer -> rechts Klick auf "Verweise" -> Projekte -> Projektmappe -> "Es wurden keine Elemente gefunden" -> Durchsuchen -> Ich kann keine Verzeichnisse hinzufügen, nur einzelne Dateien. Woran mache ich die Projektmappe aus?
    Und: was bringt mir die Einbindung der Projektmappe als Verweis für einen Vorteil im Vergleich zur .DLL?

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

    roepke schrieb:

    Das funktioniert bei mir irgendwie nicht.
    So was:

    ############################
    Klar. Studio 10 Express kann das nicht.
    Probier mal dies, im Verzeichnis, wo beide Verzeichnisse liegen, und die Extension .txt wegnehmen (sonst geht es nicht anzuhängen):
    MyProject.sln.txt
    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!

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

    Wieso steht in der .sln noch Studio10 Express bei mir?
    Das ist interessant. Damit ist das ursprüngliche Projekt mal erstellt worden.
    Ich bin aber schon seit eigenr Zeit auf VS2017 umgestigen.
    Scheinbar wird der Eintrag in der .sln nicht aktualisiert.

    Edit: OK, ich hab's gelöst. "Datei->Alles speichern" speichert die .sln-Datei nicht neu. Dafür gibt es einen extra Eintrag in "Datei" der aber nur sichtbar ist, wenn man die Solution im Projektmappen Explorer anwählt.
    Da muss man mal drauf kommen...

    Edit2: Kann es sein, dass mein Problem daher kommt, weil das Assembly oder Klassenbibliothek nicht in derselben Projektmappe ist?

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

    roepke schrieb:

    Scheinbar wird der Eintrag in der .sln nicht aktualisiert.
    Du musst das Projekt ändern, schreib statt Version 10.00 eine Version 9.00 rein, da wird das upgedatet.

    roepke schrieb:

    Kann es sein, dass mein Problem daher kommt, weil das Assembly oder Klassenbibliothek nicht in derselben Projektmappe ist?
    Das kannst Du ja jetzt testen.
    Mir ist nix aufgefallen.


    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!
    Also bei mir bekomme ich das irgendwie nicht hin.

    So sieht die Ordnerlage bei mir aus. 2 unabhängige Verzeichnisse in denen jeweils ein Projet liegt (MyDLL und MyProject).
    Möchte ich einen Verweis als Projektmappe einbinden

    kann ich keine Verzeichnis oder Proketmappe (.sln) wählen.
    Als mögliche Komponentendateien werden mir lediglich .dll, .tlb,.olb, .ocx oder .exe vorgeschlagen.
    Wähle ich die .sln ist die Anwtort

    Aber worin liegt den der Vorteil eine Projektmappe einzubinden und nicht nur die .DLL?

    roepke schrieb:

    Aber worin liegt den der Vorteil eine Projektmappe einzubinden und nicht nur die .DLL?
    Das Kopieren wird vom Studio übernommen und Du kannst in die DLL hinein debuggen.
    Kannst Du ggf. die bereinigte Projektmappe posten?
    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!
    @roepke Du musst zunächst beide Projekte in eine gemeinsame Projektmappe packen:
    MyProject.sln

    XML-Quellcode

    1. Microsoft Visual Studio Solution File, Format Version 12.00
    2. # Visual Studio Version 16
    3. VisualStudioVersion = 16.0.33328.57
    4. MinimumVisualStudioVersion = 10.0.40219.1
    5. Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "MyProject", "MyProject\MyProject.vbproj", "{045DCDBE-B192-46CB-9487-D0BF6FA94F4A}"
    6. EndProject
    7. Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "MyDLL", "MyDLL\MyDLL.vbproj", "{DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}"
    8. EndProject
    9. Global
    10. GlobalSection(SolutionConfigurationPlatforms) = preSolution
    11. Debug|Any CPU = Debug|Any CPU
    12. Debug|x86 = Debug|x86
    13. Release|Any CPU = Release|Any CPU
    14. Release|x86 = Release|x86
    15. EndGlobalSection
    16. GlobalSection(ProjectConfigurationPlatforms) = postSolution
    17. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
    18. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Debug|Any CPU.Build.0 = Debug|Any CPU
    19. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Debug|x86.ActiveCfg = Debug|Any CPU
    20. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Debug|x86.Build.0 = Debug|Any CPU
    21. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Release|Any CPU.ActiveCfg = Release|Any CPU
    22. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Release|Any CPU.Build.0 = Release|Any CPU
    23. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Release|x86.ActiveCfg = Release|Any CPU
    24. {DEEBE46A-10FC-4C54-BA8D-7784EA6B4487}.Release|x86.Build.0 = Release|Any CPU
    25. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
    26. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
    27. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Debug|x86.ActiveCfg = Debug|x86
    28. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Debug|x86.Build.0 = Debug|x86
    29. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
    30. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Release|Any CPU.Build.0 = Release|Any CPU
    31. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Release|x86.ActiveCfg = Release|x86
    32. {045DCDBE-B192-46CB-9487-D0BF6FA94F4A}.Release|x86.Build.0 = Release|x86
    33. EndGlobalSection
    34. GlobalSection(SolutionProperties) = preSolution
    35. HideSolutionNode = FALSE
    36. EndGlobalSection
    37. GlobalSection(ExtensibilityGlobals) = postSolution
    38. SolutionGuid = {F8C25B4C-B435-4857-B1EE-A73B2D47DE72}
    39. EndGlobalSection
    40. EndGlobal


    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!
    Alternativ: Öffne MyProject, dann Datei-Menü -> Hinzufügen -> Vorhandenes Projekt, dann die vbproj von MyDll (MyDll.vbproj) raussuchen, [Öffnen]
    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.
    @VaporiZed Das war auch meine Idee, aber in seinem 1. Bild in Post 11 sieht es ja so aus, als ob beide Projekte schon vereint seien. :/
    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 sieht mir eher wie ein Screenshot vom Dateiexplorer aus.
    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.
    @VaporiZed Jou. Da hat mich wohl einer mit Blindheit geschlagen. ;)
    Klar, ich hab das so gemacht wie beschrieben, allerdings habe ich zunächst die SLN in das gemeinsame Verzeichnis verschoben.
    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!