Collections in Steuerelementen

OutCasT

Grünschnabel
Hi!

Ich hab mir eine in Gruppen unterteilte Liste gebastelt. Doch wenn ich die Collection mit den Gruppen in Visual Studio bearbeite und dann das Projekt ausführe, ist die Collection wieder leer. Kann man das irgendwie mit Attributen oder ähnlichem verhindern?

thx
Marius
 
Hi!

Die Komponente ist leider noch nicht fertig. Also seht mir Fehler bezüglich Logik, Performance oder Sauberkeit nach. ;)

Die List ist ähnlich wie das TreeView aufgebaut, mit der beschränkung, dass es nur 2 Unterebenen gibt.


GroupList
+Group
++Item


Ich hab keine Idee wo der Fehler sein könnte, denn in der Komponente werden aus den Collections nur Items oder Groups gelesen, nie geschrieben.

ListGroupCollection:

Code:
Option Explicit On 
Option Strict On

Imports System
Imports System.Collections

Public Class ListGroupCollection : Inherits ArrayList

	Public Shadows Sub Add(ByVal Group As ListGroup)
		MyBase.Add(Group)
	End Sub

	Public Shadows Sub Insert(ByVal Group As ListGroup, ByVal Index As Integer)
		MyBase.Insert(Index, Group)
	End Sub

	Default Public Shadows Property Item(ByVal Index As Integer) As ListGroup
		Get
			Return CType(MyBase.Item(Index), ListGroup)
		End Get
		Set(ByVal Value As ListGroup)
			MyBase.Item(Index) = Value
		End Set
	End Property

	Public Shadows Function IndexOf(ByVal Group As ListGroup) As Integer
		Return MyBase.IndexOf(Group)
	End Function

End Class

GroupItemCollection:
Code:
Option Explicit On 
Option Strict On

Imports System
Imports System.Collections

Public Class GroupItemCollection : Inherits ArrayList

	Public Shadows Sub Add(ByVal Item As GroupItem)
		MyBase.Add(Item)
	End Sub

	Public Shadows Sub Insert(ByVal Item As GroupItem, ByVal Index As Integer)
		MyBase.Insert(Index, Item)
	End Sub

	Default Public Shadows Property Item(ByVal Index As Integer) As GroupItem
		Get
			Return CType(MyBase.Item(Index), GroupItem)
		End Get
		Set(ByVal Value As GroupItem)
			MyBase.Item(Index) = Value
		End Set
	End Property

	Public Shadows Function IndexOf(ByVal Item As GroupItem) As Integer
		Return MyBase.IndexOf(Item)
	End Function
End Class

ListGroup:

Code:
Option Explicit On 
Option Strict On

Imports System
Imports System.Drawing.Drawing2D

Public Class ListGroup
	Private m_Items As New GroupItemCollection
	Private m_Text As String
	Private Shared m_Count As Integer = 0
	Private m_Expanded As Boolean = True
	Private m_SelectionPath As New GraphicsPath
	Private m_ButtonPath As New GraphicsPath

	Friend Property ButtonPath() As GraphicsPath
		Get
			Return m_ButtonPath
		End Get
		Set(ByVal Value As GraphicsPath)
			m_ButtonPath = Value
		End Set
	End Property

	Public Sub New(ByVal Text As String)
		m_Text = Text
		m_Count += 1
	End Sub

	Public Property Expanded() As Boolean
		Get
			Return m_Expanded
		End Get
		Set(ByVal Value As Boolean)
			m_Expanded = Value
		End Set
	End Property

	Public Sub New()
		m_Count += 1
		m_Text = "Group" + m_Count.ToString()
	End Sub

	Friend Property SelectionPath() As GraphicsPath
		Get
			Return m_SelectionPath
		End Get
		Set(ByVal Value As GraphicsPath)
			m_SelectionPath = Value
		End Set
	End Property

	Public Property Items() As GroupItemCollection
		Get
			Return m_Items
		End Get
		Set(ByVal Value As GroupItemCollection)
			m_Items = Value
		End Set
	End Property

	Public Property Text() As String
		Get
			Return m_Text
		End Get
		Set(ByVal Value As String)
			m_Text = Value
		End Set
	End Property
End Class

GroupItem:

Code:
Option Explicit On 
Option Strict On

Imports System
Imports System.Drawing.Drawing2D

Public Class GroupItem
	Private m_Text As String
	Private Shared m_Count As Integer = 0
	Private m_SelectionPath As New GraphicsPath

	Public Sub New(ByVal text As String)
		m_Count += 1
		m_Text = text
	End Sub

	Public Sub New()
		m_Count += 1
		m_Text = "Item" + m_Count.ToString()
	End Sub

	Public Property Text() As String
		Get
			Return m_Text
		End Get
		Set(ByVal Value As String)
			m_Text = Value
		End Set
	End Property

	Friend Property SelectionPath() As GraphicsPath
		Get
			Return m_SelectionPath
		End Get
		Set(ByVal Value As GraphicsPath)
			m_SelectionPath = Value
		End Set
	End Property
End Class

GroupList:

Code:
Option Explicit On 
Option Strict Off

Imports System


Public Class GroupList : Inherits System.Windows.Forms.UserControl
#Region " Vom Windows Form Designer generierter Code "

	Public Sub New()
		MyBase.New()

		' Dieser Aufruf ist für den Windows Form-Designer erforderlich.
		InitializeComponent()

		m_Groups = New ListGroupCollection
		' Initialisierungen nach dem Aufruf InitializeComponent() hinzufügen

	End Sub

	' UserControl1 überschreibt den Löschvorgang zur Bereinigung der Komponentenliste.
	Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
		If disposing Then
			If Not (components Is Nothing) Then
				components.Dispose()
			End If
		End If
		MyBase.Dispose(disposing)
	End Sub

	' Für Windows Form-Designer erforderlich
	Private components As System.ComponentModel.IContainer

	'HINWEIS: Die folgende Prozedur ist für den Windows Form-Designer erforderlich
	'Sie kann mit dem Windows Form-Designer modifiziert werden.
	'Verwenden Sie nicht den Code-Editor zur Bearbeitung.
	Friend WithEvents Panel1 As System.Windows.Forms.Panel
	Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
	<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
		Me.Panel1 = New System.Windows.Forms.Panel
		Me.PictureBox1 = New System.Windows.Forms.PictureBox
		Me.SuspendLayout()
		'
		'Panel1
		'
		Me.Panel1.BackColor = System.Drawing.Color.White
		Me.Panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
		Me.Panel1.Location = New System.Drawing.Point(136, 128)
		Me.Panel1.Name = "Panel1"
		Me.Panel1.Size = New System.Drawing.Size(128, 112)
		Me.Panel1.TabIndex = 0
		Me.Panel1.Visible = False
		'
		'PictureBox1
		'
		Me.PictureBox1.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
						Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
		Me.PictureBox1.BackColor = System.Drawing.Color.White
		Me.PictureBox1.Location = New System.Drawing.Point(0, 0)
		Me.PictureBox1.Name = "PictureBox1"
		Me.PictureBox1.Size = New System.Drawing.Size(208, 72)
		Me.PictureBox1.TabIndex = 1
		Me.PictureBox1.TabStop = False
		'
		'GroupList
		'
		Me.AutoScroll = True
		Me.BackColor = System.Drawing.Color.White
		Me.Controls.Add(Me.PictureBox1)
		Me.Controls.Add(Me.Panel1)
		Me.Name = "GroupList"
		Me.Size = New System.Drawing.Size(208, 168)
		Me.ResumeLayout(False)

	End Sub

#End Region

	Protected Friend Sub Draw(ByVal G As Graphics)

		'Zählervariablen
		Dim i, j As Integer
		'Rechtecksvariablen für Gestaltung und GraphicsPath
		Dim rect As Rectangle, rectf As RectangleF
		'Aktuelle Postition der Gruppe/Item
		Dim GroupX = 0, GroupY = 0, ItemX = m_ItemsHeight, ItemY As Integer
		'StringFormat das die vertikale Ausrichtung des Texts übernimmt
		Dim fmt As New StringFormat

		fmt.LineAlignment = StringAlignment.Center
		rectf = New RectangleF(m_ItemsHeight, rect.Y, MyClass.Width - m_ItemsHeight, m_ItemsHeight)

		ItemY = m_ItemsHeight
		If Groups.Count <> 0 Then
			For i = 0 To Groups.Count - 1

				Groups(i).SelectionPath.Reset()
				Groups(i).ButtonPath.Reset()

				If Groups(i).Expanded Then

					rect = New Rectangle(GroupX, GroupY, MyClass.Width, CalcGroupHeight(Groups(i)) + 1)

					If Not m_SelectedGroup Is Groups(i) Then
						G.FillRectangle(New SolidBrush(m_SideBackColor), rect)
					ElseIf m_SelectedGroup Is Groups(i) Then
						G.FillRectangle(New SolidBrush(m_SideSelectedBackColor), rect)
					End If

					rectf = New RectangleF(m_ItemsHeight, GroupY, MyClass.Width - m_ItemsHeight, _
					 m_ItemsHeight)


					If Not m_SelectedGroup Is Groups(i) Then
						G.DrawString(Groups(i).Text, New Font("Verdana", 8, FontStyle.Bold), _
						 New SolidBrush(m_SideForeColor), rectf, fmt)
					ElseIf m_SelectedGroup Is Groups(i) Then
						G.DrawString(Groups(i).Text, New Font("Verdana", 8, FontStyle.Bold), _
						 New SolidBrush(m_SideSelectedForeColor), rectf, fmt)
					End If


					rect = New Rectangle(GroupX + 2, GroupY + 2, m_ItemsHeight - 4, m_ItemsHeight - 4)

					Groups(i).ButtonPath.AddRectangle(rect)

					If Not m_SelectedGroup Is Groups(i) Then
						G.DrawLine(New Pen(m_SideForeColor, 1), GroupX + 4, CSng(GroupY + m_ItemsHeight / 2), m_ItemsHeight - 4, _
						 CSng(GroupY + m_ItemsHeight / 2))
						G.DrawRectangle(New Pen(m_SideForeColor, 1), rect)
					ElseIf m_SelectedGroup Is Groups(i) Then
						G.DrawLine(New Pen(m_SideSelectedForeColor, 1), GroupX + 4, CSng(GroupY + m_ItemsHeight / 2), m_ItemsHeight - 4, _
						 CSng(GroupY + m_ItemsHeight / 2))
						G.DrawRectangle(New Pen(m_SideSelectedForeColor, 1), rect)
					End If


					For j = 0 To Groups(i).Items.Count - 1
						rect = New Rectangle(ItemX, ItemY, MyClass.Width - ItemX, m_ItemsHeight)

						If Not m_SelectedItem Is Groups(i).Items(j) Then
							G.FillRectangle(New SolidBrush(m_ItemsBackColor), rect)
							G.DrawRectangle(New Pen(m_GridLineColor, 1), rect)
						ElseIf m_SelectedItem Is Groups(i).Items(j) Then
							G.FillRectangle(New SolidBrush(m_ItemsSelectedBackColor), rect)
							G.DrawRectangle(New Pen(m_ItemsSelectedBackColor, 1), rect)
						End If



						Groups(i).Items(j).SelectionPath.AddRectangle(rect)
						Groups(i).SelectionPath.AddRectangle(rect)

						rectf = New RectangleF(ItemX, ItemY, MyClass.Width - ItemX, m_ItemsHeight)

						If Not m_SelectedItem Is Groups(i).Items(j) Then
							G.DrawString(Groups(i).Items(j).Text, m_ItemFont, New SolidBrush(m_ItemsForeColor), _
							 rectf, fmt)
						ElseIf m_SelectedItem Is Groups(i).Items(j) Then
							G.DrawString(Groups(i).Items(j).Text, m_ItemFont, New SolidBrush(m_ItemsSelectedForeColor), _
							 rectf, fmt)
						End If

						ItemY += m_ItemsHeight
					Next

				ElseIf Not Groups(i).Expanded Then
					rect = New Rectangle(GroupX, GroupY, MyClass.Width, m_ItemsHeight)
					G.FillRectangle(New SolidBrush(m_SideBackColor), rect)

					rectf = New RectangleF(m_ItemsHeight, GroupY, MyClass.Width - m_ItemsHeight, _
					 m_ItemsHeight)

					Groups(i).SelectionPath.AddRectangle(rect)

					G.DrawString(Groups(i).Text, New Font("Verdana", 8, FontStyle.Bold), _
					 New SolidBrush(m_SideForeColor), rectf, fmt)

					rect = New Rectangle(GroupX + 2, GroupY + 2, m_ItemsHeight - 4, m_ItemsHeight - 4)

					G.DrawRectangle(New Pen(m_SideForeColor, 1), rect)
					Groups(i).ButtonPath.AddRectangle(rect)

					G.DrawLine(New Pen(m_SideForeColor, 1), GroupX + 4, CSng(GroupY + m_ItemsHeight / 2), m_ItemsHeight - 4, _
					 CSng(GroupY + m_ItemsHeight / 2))
					G.DrawLine(New Pen(m_SideForeColor, 1), CSng(m_ItemsHeight / 2), CSng(GroupY + 4), CSng(m_ItemsHeight / 2), _
					 GroupY + m_ItemsHeight - 4)
				End If
				GroupY += CalcGroupHeight(Groups(i))

				ItemY += m_ItemsHeight
			Next
		End If
		PictureBox1.Height = CalcAllGroupHeight()
	End Sub

	Private Function CalcGroupHeight(ByVal g As ListGroup) As Integer
		Dim h As Integer
		If g.Expanded Then
			h = (g.Items.Count * m_ItemsHeight) + m_ItemsHeight
		ElseIf Not g.Expanded Then
			h = m_ItemsHeight
		End If
		Return h
	End Function

	Private Function CalcAllGroupHeight() As Integer
		Dim h, i As Integer
		For i = 0 To Groups.Count - 1
			h += CalcGroupHeight(Groups(i))
		Next

		Return h + 1
	End Function

	Private Sub GroupList_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		PictureBox1.Height = CalcAllGroupHeight()
		Redraw()
		'Draw(PictureBox1.CreateGraphics())

	End Sub

	Public Property BorderStyle() As BorderStyle
		Get
			Return PictureBox1.BorderStyle
		End Get
		Set(ByVal Value As BorderStyle)
			PictureBox1.BorderStyle = Value
		End Set
	End Property

	Public Sub Redraw()
		Draw(PictureBox1.CreateGraphics())
	End Sub

	Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
		Draw(e.Graphics)
	End Sub

	Private Sub PictureBox1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Resize
		Redraw()
	End Sub

	Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
		Dim i, j As Integer
		Dim changed As Boolean = False

		For i = 0 To Groups.Count - 1
			If Groups(i).ButtonPath.IsVisible(e.X, e.Y) Then
				Groups(i).Expanded = Not Groups(i).Expanded
				changed = True
			else If Groups(i).SelectionPath.IsVisible(e.X, e.Y) Then
				m_SelectedGroup = Groups(i)
				m_SelectedGroupIndex = i
				changed = True
				If Groups(i).Expanded Then
					For j = 0 To Groups.Count - 1
						If Groups(i).Items(j).SelectionPath.IsVisible(e.X, e.Y) Then
							changed = True
							m_SelectedItem = Groups(i).Items(j)
							m_SelectedItemIndex = j
							Exit For
						End If
					Next
				End If
				If Not Groups(i).Expanded Then
					m_SelectedItem = Nothing
					m_SelectedItemIndex = -1
				End If
				Exit For
			End If
		Next
		If changed Then Redraw()
	End Sub

	Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
		Dim i, j As Integer
		Dim changed As Boolean = False
		For i = 0 To Groups.Count - 1
			If Groups(i).SelectionPath.IsVisible(e.X, e.Y) Then
				m_SelectedGroup = Groups(i)
				m_SelectedGroupIndex = i
				changed = True
				If Groups(i).Expanded Then
					For j = 0 To Groups.Count - 1
						If Groups(i).Items(j).SelectionPath.IsVisible(e.X, e.Y) Then
							changed = True
							m_SelectedItem = Groups(i).Items(j)
							m_SelectedItemIndex = j
							Exit For
						End If
					Next
				End If
				If Not Groups(i).Expanded Then
					m_SelectedItem = Nothing
					m_SelectedItemIndex = -1
				End If
				Exit For
			End If
		Next
		If changed Then Redraw()
	End Sub
End Class

Ich hoffe das war genug sourcecode :)

thx
Marius
 
Zuletzt bearbeitet:
Boah Junge, nur den Quelltext der entsprechenden Stelle, nicht das ganze Projekt. Mein Gehirn kann vieles, aber nicht soviel Quelltext auf einmal debuggen. *fg* ;)

Ich stell mir gerade vor was passiert wäre wenn ich statt "ein wenig Code" unvorsichtigerweise "viel Code" geschrieben hätte ... ich glaub dann wär die Datenbank hier voll. :)

Welche Stelle meinst Du denn?
 
Das war nicht das ganze Projekt, das waren nur die Stellen, die vielleicht wichtig sein könnten. Ich musste nämlich mit den 15000 Zeichen kämpfen ;)

Es ist recht schwer, die entsprechende Stelle zu posten, wenn man absolut keinen blassen Dunst hat, wo der Fehler liegen könnte :(
Mein Problem ist ja, wenn ich in Visual Studio im Designer die Collections mit den Groups und den Items bearbeite und dann ausführe oder das Projekt später wieder lade, ist die List auf einmal wieder leer. Ich such also ne Lösung die Einträge dauerhaft persistent zu machen...
Beim TreeView fügt der Designer ja die Zeile TW.AddRange(...) ein. Bei meiner GroupList nicht.

Code:
Me.TreeView1.Nodes.AddRange(New System.Windows.Forms.TreeNode() {New System.Windows.Forms.TreeNode("Knoten0", New System.Windows.Forms.TreeNode() {New System.Windows.Forms.TreeNode("Knoten1")}), New System.Windows.Forms.TreeNode("Knoten2", New System.Windows.Forms.TreeNode() {New System.Windows.Forms.TreeNode("Knoten3", New System.Windows.Forms.TreeNode() {New System.Windows.Forms.TreeNode("Knoten4"), New System.Windows.Forms.TreeNode("Knoten5")}), New System.Windows.Forms.TreeNode("Knoten6")})})


Ich kann mir vorstellen, dass ich in den Collections vielleicht irgendwas falsch mache. Denn in der Load-Prozedur von der Komponente wird nur die Höhe der PictureBox, in der das ganze gezeichnet wird, verändert. Vielleicht kann man auch mit Hilfe von Attributen sowas wie AddRange() einfügen

Code:
Option Explicit On 
Option Strict On

Imports System
Imports System.Collections

Public Class GroupItemCollection : Inherits ArrayList

	Public Shadows Sub Add(ByVal Item As GroupItem)
		MyBase.Add(Item)
	End Sub

	Public Shadows Sub Insert(ByVal Item As GroupItem, ByVal Index As Integer)
		MyBase.Insert(Index, Item)
	End Sub

	Default Public Shadows Property Item(ByVal Index As Integer) As GroupItem
		Get
			Return CType(MyBase.Item(Index), GroupItem)
		End Get
		Set(ByVal Value As GroupItem)
			MyBase.Item(Index) = Value
		End Set
	End Property

	Public Shadows Function IndexOf(ByVal Item As GroupItem) As Integer
		Return MyBase.IndexOf(Item)
	End Function

End Class

Public Class ListGroupCollection : Inherits ArrayList

	Public Shadows Sub Add(ByVal Group As ListGroup)
		MyBase.Add(Group)
	End Sub

	Public Shadows Sub Insert(ByVal Group As ListGroup, ByVal Index As Integer)
		MyBase.Insert(Index, Group)
	End Sub

	Default Public Shadows Property Item(ByVal Index As Integer) As ListGroup
		Get
			Return CType(MyBase.Item(Index), ListGroup)
		End Get
		Set(ByVal Value As ListGroup)
			MyBase.Item(Index) = Value
		End Set
	End Property

	Public Shadows Function IndexOf(ByVal Group As ListGroup) As Integer
		Return MyBase.IndexOf(Group)
	End Function
End Class

Aber trotzdem danke für die Antwort :)
 
Zurück