Tabcontrol als MDI Container >> EDIT: Basis, Form2 auf Form1 in Basis

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

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von michl75.

    Tabcontrol als MDI Container >> EDIT: Basis, Form2 auf Form1 in Basis

    Hallo,

    ich bin gerade am experimentieren. Ob's nun so ast rein ist, weis ich ned und nen feinschliff bekommt auch erst später.

    Versuche einer Forderung all unserer Außendienstmitarbeiter nachzukommen. Daher die Idee nach MDI ähnlicher Umsetzung.

    Aufbau:

    1. Normales Form mit Menüs und einem TreeView (stehen alle Anwendungen drinnen)

    2. TabControl (eigenes, wg. Farbe ... naja, ob auch dies so ne gute Idee war, aber das hässliche grau passte 0,0 zum Programm )

    3. Es werden die Anwendungen wie z. B. Kundenstamm, Berichtswesen, Auftragswesen usw. bei Klick im Treeview im missbrauchen TabControl angezeigt.

    4. Das Problem: Wie kann ich nun das ChildForm schließen und dabei auch gleich den Reiter entfernen? ...Reiter klar mit Tabblabl.remove ... aber worüber ich mir den Kopf zerbreche ist, wie macht ich das voneinander abhängig?

    Mein Code:

    Erstmal das eigene TabControl als Klasse:

    VB.NET-Quellcode

    1. Public Class CLM_TabControl1
    2. Inherits TabControl
    3. Public Class RiderClickedEventArgs
    4. Inherits EventArgs
    5. Public ReadOnly TabPage As TabPage
    6. Public ReadOnly Index As Integer
    7. Public Sub New(ByVal Index As Integer, ByVal TabPage As TabPage)
    8. Me.Index = Index
    9. Me.TabPage = TabPage
    10. End Sub
    11. End Class
    12. Public Event RiderClicked As EventHandler(Of RiderClickedEventArgs)
    13. Private _Brush As New SolidBrush(Color.FromArgb(199, 227, 255))
    14. Private ReadOnly _Disableds As New List(Of Control)
    15. Public Sub New()
    16. Me.DrawMode = TabDrawMode.OwnerDrawFixed
    17. End Sub
    18. Protected Overrides Sub OnClick(ByVal e As EventArgs)
    19. Dim Indx As Integer = GetTabRider(Me.PointToClient(Control.MousePosition))
    20. If Indx < 0 OrElse Not IsTabEnabled(Indx) Then Return
    21. RaiseEvent RiderClicked(Me, New RiderClickedEventArgs(Indx, TabPages(Indx)))
    22. End Sub
    23. Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    24. If disposing Then
    25. _Brush.Dispose()
    26. End If
    27. MyBase.Dispose(disposing)
    28. End Sub
    29. Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
    30. MyBase.OnDrawItem(e)
    31. Const tff As TextFormatFlags = TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter
    32. Dim tp As TabPage = MyBase.TabPages(e.Index)
    33. Dim rct As Rectangle = e.Bounds
    34. Dim g As Graphics = e.Graphics
    35. If _Disableds.Contains(tp) Then
    36. _Brush.Color = Color.FromArgb(199, 227, 255) 'SystemColors.Control
    37. g.FillRectangle(_Brush, rct)
    38. ControlPaint.DrawStringDisabled(g, tp.Text, Me.Font, Color.FromArgb(199, 227, 255), rct, tff)
    39. Else
    40. _Brush.Color = Color.FromArgb(199, 227, 255) ' tp.BackColor
    41. g.FillRectangle(_Brush, rct)
    42. TextRenderer.DrawText(g, tp.Text, Me.Font, rct, tp.ForeColor, tff)
    43. End If
    44. End Sub
    45. Private Function GetTabRider(ByVal Pt As Point) As Integer
    46. For I As Integer = 0 To Me.TabPages.Count - 1
    47. If Me.GetTabRect(I).Contains(Pt) Then Return I
    48. Next
    49. Return -1
    50. End Function
    51. Public Property IsTabEnabled(ByVal Index As Integer) As Boolean
    52. Get
    53. Return Not _Disableds.Contains(MyBase.TabPages(Index))
    54. End Get
    55. Set(ByVal Value As Boolean)
    56. IsTabEnabled(MyBase.TabPages(Index)) = Value
    57. End Set
    58. End Property
    59. Public Property IsTabEnabled(ByVal Tp As TabPage) As Boolean
    60. Get
    61. Return Not _Disableds.Contains(Tp)
    62. End Get
    63. Set(ByVal Value As Boolean)
    64. If _Disableds.Contains(Tp) <> Value Then Return
    65. Tp.Enabled = Value
    66. If Value Then
    67. _Disableds.Remove(Tp)
    68. Else
    69. _Disableds.Add(Tp)
    70. End If
    71. Me.Invalidate(New Rectangle(0, 0, Me.Width, Me.GetTabRect(0).Height))
    72. End Set
    73. End Property
    74. End Class


    Dann der Code für das öffnen des Programms:

    VB.NET-Quellcode

    1. Private Sub OpenFormAsString(ByVal formname As String)
    2. Dim f As New Form
    3. For Each t As Type In Me.GetType().Assembly.GetTypes()
    4. If t.Name.Equals(formname) Then
    5. f = System.Activator.CreateInstance(t)
    6. f.TopLevel = False
    7. f.Visible = True
    8. ' Neuen Reiter vorbereiten und einfügen
    9. Dim myTabPage As New TabPage(t.ToString)
    10. ClM_TabControl11.TabPages.Add(myTabPage)
    11. Dim tabPage As New TabPage
    12. ' Neuen Reiter suchen, Controlseinfügen und selektieren
    13. For Each tabPage In ClM_TabControl11.TabPages
    14. If tabPage.Text = t.ToString Then
    15. tabPage.Controls.Add(f)
    16. tabPage.Select()
    17. End If
    18. Next
    19. ClM_TabControl11.SelectedTab = tabPage
    20. ClM_TabControl11.Controls.Add(f)
    21. f.BringToFront()
    22. End If
    23. Next
    24. End Sub


    Das funktioniert soweit auch gut, kein Fehlermeldungen nix! Läuft auch länger stabil auch bei vielen offenen Anwendungen und Reitern.

    Nun aber ... ich weis nicht wie ich es von einander abhängig machen kann, dass wenn Form geschlossen wird auch der Reiter verschwindet oder evtl. noch besser... ein X in den Reiter rein, der das ChildForm schließt und den Reiter wegmacht.

    Außerdem habe ich festgestellt, vielleicht hat dazu einer nen Tipp... bei meinem "eigenen" TabControl werden keine Images angezeigt, wenn ich dies hinterlegt.

    Wäre nett wenn einer was zu meinem "Missbrauch" vom TabControl was sagt :) Irgendwie abartig, aber es funktioniert und Erfindergeist hat was :D

    Vielen Dank vorab! Gruß Michl

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

    Schreib doch ne Event in der Childform, welches von der Haupt Form abonniert wurde. Dieses muss dann beim Closing event des Childforms ausgelöst werden und du kannst reagieren.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    AddHandler Form2 soll ich Form1 etwas auslösen... tut er aber nicht hhmm...

    Hallo,

    @ErfinderDesRades : Danke, hat geholfen... habe mir mal angeschaut und versucht umzusetzen. Solange es einfache Sachen ist, verständlich...

    Mit

    Quellcode

    1. AddHandler frm.FormClosing, AddressOf TabConbtrolPgmClear
    war dann recht "schnell" das FormClosing Event abonniert. Nochmals Danke!

    Nun komme ich zu einem weiteren Problem, was mich eben beschäftigt und ich gerade über die Wirkung unsicher bin... weil ein komisches Verhalten auftritt (was ich bestimmt selbst auslöse durch gedönscode)....

    Kurze Zusammenfassung:

    1 .Ich habe ein Form ( FORM1 ) in dem habe ich ein Menue habe als TreeView (statisch vorgegebene Werte) und ein TapControl gesetzt.
    2. Ich öffne per doppelclick im Treeview in einem neuen Tab ein Form ( FORM2 ) ähnlich MDI
    3. Im FORM2 habe ich ein Datagridview, mache ich Doppelklick darauf soll wieder in FORM1 im TabControl ein weiteres Tab erstellt werden und darin das FORM3 reinkommen.

    EDIT:
    Und dann mal fast nach Anleitung:

    Form1 (Basis):
    Klick im Menü FORM1 ...

    VB.NET-Quellcode

    1. Private Sub TreeView1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TreeView1.DoubleClick
    2. Try
    3. PrintRecursive()
    4. NewTap_intern(Me, New DataTransferEventArgs(TreeView1.SelectedNode.Tag.ToString))
    5. Catch ex As Exception
    6. End Try
    7. End Sub


    VB.NET-Quellcode

    1. Public Sub NewTap_intern(sender As Object, e As DataTransferEventArgs) 'ByVal formname As String)
    2. Dim frm As Form
    3. For Each t As Type In Me.GetType().Assembly.GetTypes()
    4. If t.Name.Equals(e.Data) Then
    5. frm = System.Activator.CreateInstance(t)
    6. frm.TopLevel = False
    7. frm.Visible = True
    8. ' Neuen Reiter vorbereiten und einfügen
    9. TsLbl_Test.Text = t.ToString
    10. Dim myTabPage As New TabPage(t.ToString)
    11. CLM_TabConPgms.TabPages.Add(myTabPage)
    12. ' Neuen Reiter suchen, Controlseinfügen und selektieren
    13. For Each tabPage In CLM_TabConPgms.TabPages
    14. If tabPage.Text = t.ToString Then
    15. tabPage.Controls.Add(frm)
    16. AddHandler frm.FormClosing, AddressOf TabConbtrolPgmClear
    17. ' Abo's
    18. Select Case e.Data
    19. Case "TelefonVerwaltung_01"
    20. AddHandler TelefonVerwaltung_01.DataTransfer, AddressOf NewTap_intern 'Event abbonnieren
    21. End Select
    22. End If
    23. Next
    24. CLM_TabConPgms.SelectedTab = myTabPage
    25. frm.BringToFront()
    26. frm.Dock = DockStyle.Fill
    27. Exit For
    28. End If
    29. Next
    30. End Sub


    Dann FORM2 mit Datagridview:

    VB.NET-Quellcode

    1. Public Event DataTransfer As EventHandler(Of DataTransferEventArgs)
    2. Private Sub PersonenstammDataGridView_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles PersonenstammDataGridView.MouseDoubleClick
    3. RaiseEvent DataTransfer(Me, New DataTransferEventArgs("BearbeitungPersonen"))
    4. End Sub


    Im FORM2 Doppelclick in DGV:

    VB.NET-Quellcode

    1. Private Sub PersonenstammDataGridView_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles PersonenstammDataGridView.MouseDoubleClick
    2. RaiseEvent DataTransfer(Me, New DataTransferEventArgs("BearbeitungPersonen"))
    3. End Sub

    Dann die DataTransfer-Klasse:

    VB.NET-Quellcode

    1. Public Class DataTransferEventArgs
    2. Inherits EventArgs
    3. Public Sub New(data As String)
    4. Me.Data = data
    5. End Sub
    6. Public ReadOnly Data As String
    7. End Class


    Ergebnis: Wieder kein Erfolg, die

    Quellcode

    1. NewTap_intern
    wird nicht ausgeführt wenn ich in FORM2 Doppelclick in DGV mache und ich hab festgestellt, dass der Parameter "BearbeitungPersonen" nicht übergeben wird ... Was mache ich den nur falsch? ....

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „michl75“ ()

    mrMo schrieb:

    Schreib doch ne Event in der Childform, welches von der Haupt Form abonniert wurde. Dieses muss dann beim Closing event des Childforms ausgelöst werden und du kannst reagieren


    Danke ... habe ich dann so gemacht:

    VB.NET-Quellcode

    1. ' Neuen Reiter suchen, Controlseinfügen und selektieren
    2. For Each tabPage In CLM_TabConPgms.TabPages
    3. If tabPage.Text = t.ToString Then
    4. tabPage.Controls.Add(frm)
    5. AddHandler frm.FormClosing, AddressOf TabConbtrolPgmClear
    6. ...


    und das schließen funktioniert bestens ! Danke...
    Guten Morgen,

    es hat mir keine Ruihe gelassen und heute morgen dachte ich mir, vielleicht "sperrt" das Form im Form (in Tap) Irgendwie das "Hauptform"... Darum habe ich NUR um zu testen mal in der Hauptform einen Backgroudworker eingesetzt auf einfache dämliche Art und weise... und siehe da... jetzt wird ein Tap angelegt.

    VB.NET-Quellcode

    1. Private Sub Timer_BGWTabControl_Tick(sender As Object, e As EventArgs) Handles Timer_BGWTabControl.Tick
    2. BGW_TabControl.RunWorkerAsync()
    3. TsLbl_Test.Text = "Läuft "
    4. End Sub
    5. Private Sub BGW_TabControl_DoWork(sender As Object, e As DoWorkEventArgs) Handles BGW_TabControl.DoWork
    6. If __NewTapName <> Nothing Then
    7. BGW_TabControl.ReportProgress(1)
    8. End If
    9. End Sub
    10. Private Sub BGW_TabControl_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BGW_TabControl.ProgressChanged
    11. TsLbl_Test.Text = "Läuft ..... " ' & Date.Now.ToString("t")
    12. If e.ProgressPercentage = 1 Then
    13. Dim _vorhanden As Boolean = False
    14. For Each tabPage In CLM_TabConPgms.TabPages
    15. If tabPage.Text = __NewTapName Then
    16. _vorhanden = True
    17. End If
    18. Next
    19. If _vorhanden = False Then
    20. NewTap_intern(Me, New DataTransferEventArgs(__NewTapName))
    21. End If
    22. __NewTapName = ""
    23. End If
    24. End Sub
    25. Public Sub NewTap_intern(sender As Object, e As DataTransferEventArgs) 'ByVal formname As String)
    26. ....


    Also gehe ich mal davon aus, das die Hauptform nicht aktiv ist bzw. iwie gesperrt ist und dadurch letztendlich AddHandles dann auch ned umgesetzt wird.

    Sehe schon, doofe Idee3 das Form in Form...