Rodermund Konstruktion und Entwicklung GmbH

Maschinenbau · Konstruktion · Entwicklung · Berechnung · Schulung · Beratung

Erstellen eines flexiblen Auswahldialogs mit WindowsForms und ListBox in Inventor-Regeln

Ein Auswahldialog, der automatisch die Namen der meisten Inventor-API Objekte anzeigt, das gewählte Objekt und DialogResult zurückgibt und anpassbar ist

Links zum Thema:
Das Video zum flexiblen Inventor-API Auswahldialog bei Youtube oder DailyMotion .

Warum ein selbst gebauter Auswahldialog?

Die Inventor-API bietet, um Benutzer aus einer Liste etwas wählen zu lassen, nur die iLogic InputListBox bzw. den InputListBoxDialog. Diese verlangen als Eingabe eine Liste von Strings oder Objekten, deren .ToString Methode verwendet wird, um die angezeigte Liste zu füllen. Die meisten Inventor-Objekte liefern mit .ToString aber nur ihre Typbezeichnung "System.__Com-Object" zurück. Um das zu kompensieren, kenne ich bisher nur den workaround, der von Jelte de Jong vorgeschlagen wurde und für viele Fälle ausreicht: Zuerst werden alle Objekte der Liste in neue Objekte einer Wrapperklasse mit angepasster .ToString Methode verpackt, und dann der InputListBox eine Liste mit Wrapperopjekten übergeben, was manchmal etwas umständlich erscheint. Außerdem ist dann auch der Rückgabewert der InputListBox ein Wrapperobjekt und nicht das Objekt, mit dem weiter gearbeitet wird.

Zwar kann man, wenn man einen InputListBoxDialog deklariert und ShowDialog aufruft, ein DialogResult erhalten und auf einige Eigenschaften wie z. B. das gewählte Objekt und den gewählten Index zugreifen nach Schließen des Dialogs. Allerdings erhält man auch hier anscheinend keine Möglichkeit, den angezeigten Inhalt der Liste zu beeinflussen, da diese erst nach dem Aufruf von ShowDialog gefüllt wird. Man kann die angezeigten Strings also nicht gegen die tatsächlichen Objektnamen tauschen.

Deshalb habe ich eine eigene AuswahlDialog Klasse geschrieben, die aus einer Objektliste die üblichen Namenseigenschaften ausliest und anzeigt, das gewählte Objekt zurückgibt und auch den DialogResult. Da der Dialog wie üblich bei WindowsForms vor dem Anzeigen als Objekt angelegt wird, können alle Eigenschaften des Dialogs angepasst werden.

Hier erkläre ich den Code zuerst Abschnittsweise, am Ende folgt der komplette Code.

Werkstoffauswahl mit InputListBox ohne Wrapper
Bild 1: Werkstoffauswahl mit InputListBox ohne Wrapper

Main-Methode und Verwendung des Dialogs

Zuerst die Einleitung: Wir importieren die Fensterverwaltung für Windows-apps und Reflection, um Typeigenschaften abfragen zu können. Dann kommt die main-Methode. Das sind die Voraussetzungen für die Verwendung der AuswahlDialog Klasse. Damit wir den Dialog mittig auf dem Inventor-Hauptfenster platzieren können, brauchen wir dessen Geometrie.

Imports System.Windows.Forms
Imports System.Reflection

Sub Main()
    Dim invApp As Inventor.Application = ThisApplication
    Dim width As Integer = invApp.Width
    Dim height As Integer = invApp.Height
    Dim links As Integer = invApp.Left
    Dim oben As Integer = invApp.Top
    Dim fenstermitte As Point2d = invApp.TransientGeometry.CreatePoint2d(links + width \ 2, oben + height \ 2)

Als nächstes wird das parametrisch typisierte Dialogfenster erzeugt. Was dabei genau passiert kommt bei der Erklärung der Klasse. In diesem Fall soll eine Liste von Werkstoffen ausgegeben werden, die in einer als Beispiel willkürlich gewählten Werkstoffbibliothek enthalten sind. Die Dialogfenstergröße wird mit der Anpassungsmethode an die Anzahl der Werkstoffe angepasst. Die Höhe ist die Höhe des Inventorfensters, weil es mir aus Inventor heraus nicht gelungen ist, die Bildschirmhöhe zu lesen. Ähnliches gilt für die Position, die auf die Mitte des Inventor-Fensters gesetzt wird. Eine Schaltfläche wird umbenannt.

    
    Dim werkstoffauswahlDialog As New AuswahlDialog(Of Asset)(invApp.AssetLibraries(2).MaterialAssets)
    werkstoffauswahlDialog.Text = "Werkstoff auswählen"
    werkstoffauswahlDialog.ButtonOK.Text = "Auswählen"
    werkstoffauswahlDialog.AdjustWindowHeight(height)
    werkstoffauswahlDialog.SetPos(fenstermitte.X - werkstoffauswahlDialog.Width \ 2, fenstermitte.Y - werkstoffauswahlDialog.Height \ 2)

Der nächste Abschnitt zeigt den erstellten Dialog modal an, wartet auf Eingabe und verarbeitet die Benutzerauswahl. Wenn der Benutzer "OK" wählt, wird das ausgewählte Asset in der Variablen werkstoff gespeichert. Wenn ein Werkstoff ausgewählt wurde, wird dessen Name ausgegeben; hier würde normalerweise natürlich irgendetwas mit dem gewählten Werkstoff passieren. Bei Abbruch wird eine Meldung protokolliert und die Subroutine beendet. Das könnte man auch schon vorher machen, wenn man auf DialogResult.Cancel prüft.

    Dim werkstoff As Asset = Nothing
    Dim antwort As DialogResult = werkstoffauswahlDialog.ShowDialog()
    If antwort = DialogResult.OK Then
        werkstoff = werkstoffauswahlDialog.SelectedItem
    End If
    If werkstoff IsNot Nothing Then
        Logger.Info(werkstoff.DisplayName & " ausgewählt.")
    Else
        Logger.Info("Kein Werkstoff ausgewählt.")
        Exit Sub
    End If
End Sub

Aufbau des Dialogs

Der nächste Codeabschnitt definiert den Kern des Themas: Die Klasse AuswahlDialog, die von Form (einem Windows-Fenster) erbt und überwiegend automatisch von Visual Studio generiert wurde. Außerdem wird ein generischer Typ T verwendet. Der Typ ermöglicht es uns, genau so ein Objekt zurückzugeben, wie wir in der Liste erhalten haben. Die Steuerelemente ListBox1, ButtonOK und ButtonCancel sowie Eigenschaften für den ausgewählten Index (SelectedIndex), das ausgewählte Element (SelectedItem), einen Adapter (Adapter; dazu später mehr) und die anzuzeigenden Elemente (Items). Das SelectedItem soll den parametrischen Typ annehmen. Der Konstruktor der Klasse initialisiert den Dialog, indem er die Anzahl der Elemente in der übergebenen IEnumerable ermittelt. Dabei werden verschiedene Möglichkeiten zur Bestimmung der Anzahl ausprobiert (Length-Property, Count-Property, Count-Methode oder durch Iteration), weil es in Inventor verschiedene Typen von Objektsammlungen geben kann. Wenn gar kein direkter Weg zum Ermitteln der Anzahl gefunden wird, zählen wir einfach durch.

Public Class AuswahlDialog(Of T)
    Inherits Form

    Private ReadOnly ListBox1 As New ListBox()
    Friend ButtonOK As New Button()
    Friend ButtonCancel As New Button()

    Public Property SelectedIndex As Integer
    Public Property SelectedItem As T
    Private Property Adapter As IObjektAdapter
    Private Property Items As IEnumerable

    Public Sub New(items As IEnumerable, Optional adapter As IObjektAdapter = Nothing, Optional startIndex As Integer = -1)
        Dim anzahl As Integer = 0
        Dim listTypeInfo As Type = items.GetType()
        Dim prop As System.Reflection.PropertyInfo
        prop = listTypeInfo.GetProperty("Length")
        If prop Is Nothing Then
            prop = listTypeInfo.GetProperty("Count")
        End If
        If prop IsNot Nothing Then
            anzahl = prop.GetValue(items)
        Else
            Dim met As System.Reflection.MethodInfo
            met = listTypeInfo.GetMethod("Count")

            If met IsNot Nothing Then
                anzahl = listTypeInfo.GetMethod("Count").Invoke(items, Nothing)
                anzahl = met.Invoke(items, Nothing)
            Else
                For Each item As Object In items
                    anzahl += 1
                Next
            End If
        End If

Bestimmen der Auswertungsart zur Erzeugung der Listenanzeige

Dieser Abschnitt bestimmt, wie die Elemente in der ListBox angezeigt werden sollen. Wenn kein Adapter übergeben wurde, versucht der Code, die anzuzeigenden Werte automatisch zu ermitteln. Dazu prüft er, ob die Elemente eine DisplayName-Property, eine Name-Property oder eine ToString-Methode haben. Wenn ein Adapter vorhanden ist, der die Methode zur Erzeugung der Stringliste enthält, wird dieser für die Anzeige verwendet. Der Code greift zur Laufzeit dynamisch auf die Eigenschaften der Objekte zu und behandelt Exceptions, falls die erwarteten Properties nicht vorhanden sind. Welche Möglichkeit zur Anzeige gewählt wurde, wird in der Enum auswertung festgelegt.

        Dim auswertung As Auswertungsart = Auswertungsart.AuswertungNichts
        Me.Items = items
        If adapter Is Nothing Then
            Dim typeInfo As Type = Nothing

            If typeInfo Is Nothing Then
                typeInfo = GetType(T)
            End If

            If typeInfo Is GetType(String) Then
                auswertung = Auswertungsart.AuswertungString
            ElseIf typeInfo.GetProperty("DisplayName") IsNot Nothing Or typeInfo.GetMethod("DisplayName") IsNot Nothing Then
                auswertung = Auswertungsart.AuswertungDisplayName
            ElseIf typeInfo.GetProperty("Name") IsNot Nothing Then
                auswertung = Auswertungsart.AuswertungName
            ElseIf typeInfo.GetMethod("ToString") IsNot Nothing Then
                auswertung = Auswertungsart.AuswertungToString
            End If

            If auswertung = Auswertungsart.AuswertungNichts Then
                Dim test As String
                Try
                    test = Me.Items(0).DisplayName
                    auswertung = Auswertungsart.AuswertungDisplayName
                Catch
                    Try
                        test = Me.Items(0).Name
                        auswertung = Auswertungsart.AuswertungName
                    Catch
                    End Try
                End Try
            End If


        Else
            Me.Adapter = adapter
        End If

Konfiguration des Dialogs und Füllen der Listbox

Neben einigen Eigenschaften des Dialogs wird hier die ListBox konfiguriert und das Fenster zusammengebaut. Viel davon ist automatisch generiert, nur der Inhalt der Listbox ist manuell geschrieben. Die Elemente werden in die Liste eingetragen, wobei die vorher ermittelte Auswertungsart berücksichtigt wird. Falls ein Adapter übergeben wurde, wird die Stringliste von dem bezogen. Die Auswahl wird auf den übergebenen Startindex gesetzt, falls dieser gültig ist. Die Schaltflächen werden konfiguriert und die Größe des Dialogs wird angepasst.

        Me.Text = "Auswahl treffen"
        Me.Width = 320
        Me.Height = 300

        Me.StartPosition = FormStartPosition.CenterScreen

        If Me.Adapter IsNot Nothing Then
            ListBox1.Items.AddRange(Me.Adapter.GetStringArray(Me.Items, anzahl))
        Else
            For i As Integer = 0 To anzahl - 1
                Select Case auswertung
                    Case Auswertungsart.AuswertungString
                        ListBox1.Items.Add(CType(items(i), String))
                    Case Auswertungsart.AuswertungDisplayName
                        ListBox1.Items.Add(items(i).DisplayName)
                    Case Auswertungsart.AuswertungName
                        ListBox1.Items.Add(items(i).Name)
                    Case Auswertungsart.AuswertungToString
                        ListBox1.Items.Add(items(i).ToString())
                    Case Else
                        ListBox1.Items.Add("keine passende Auswertungsart gefunden")
                End Select
            Next
        End If
        ListBox1.Dock = DockStyle.Top
        AddHandler ListBox1.SelectedIndexChanged, AddressOf ListBox_SelectedIndexChanged
        Me.Controls.Add(ListBox1)

        Dim panel As New FlowLayoutPanel()
        panel.FlowDirection = FlowDirection.RightToLeft
        panel.Dock = DockStyle.Bottom
        panel.Height = 40

        ButtonOK.Text = "OK"
        ButtonOK.Enabled = False
        AddHandler ButtonOK.Click, AddressOf ButtonOK_Click
        panel.Controls.Add(ButtonOK)

        If startIndex < anzahl - 1 Then
            Me.SelectedIndex = startIndex
        Else
            Me.SelectedIndex = -1
        End If

        If Me.SelectedIndex > -1 Then 
            ListBox1.SelectedIndex = startIndex
            Me.SelectedItem = CType(Me.Items(startIndex),T)
        End If

        ButtonCancel.Text = "Abbrechen"
        AddHandler ButtonCancel.Click, AddressOf ButtonCancel_Click
        panel.Controls.Add(ButtonCancel)

        Me.Controls.Add(panel)
        Me.MaximizeBox = False
        Me.MinimizeBox = False
        Me.AutoSize = True
        Me.AdjustWindowHeight()
    End Sub

Methoden zum Anpassen von Position und Größe

Die beiden Methoden SetPos und AdjustWindowHeight dienen dazu, den Dialog an die gewünschte Position zu setzen und die Höhe des Dialogs anzupassen. Die Position wird relativ zum Inventor-Fenster gesetzt, die Höhe wird so angepasst, dass die Liste nicht zu lang wird und die Schaltflächen nicht zu weit unten stehen. Die Höhe des Dialogs wird auf die Höhe der Schaltflächen, der Liste und einiger Abstände gesetzt. Hier war einiges an Gebastel nötig, weil einige oft benutzten Methoden und Properties (z. B. ClientSize) für das Fensterlayout Klassen aus System.Drawing.Primitives verwenden, die in Inventor anscheinend nicht verfügbar sind. Da es mir nicht gelungen ist, die benötigten Klassen zu importieren, habe ich die Methoden so umgeschrieben, dass sie ohne diese Klassen auskommen. Falls jemand mir sagen kann, wie ich diese Klassen (z. B. Rectangle oder Pointverwenden kann, bitte ich um Hinweis.

    Public Sub SetPos(links As Integer, oben As Integer)
        Me.StartPosition = FormStartPosition.Manual
        Me.Left = links
        Me.Top = oben
    End Sub

    Public Sub AdjustWindowHeight(Optional maxHoehe As Integer = 1000)

        Dim screenHeight As Integer = maxHoehe

        Dim maxlistBoxHeight As Integer = screenHeight \ 2
        Dim listBoxHeight As Integer = Math.Min(ListBox1.ItemHeight * ListBox1.Items.Count + 30, maxlistBoxHeight)

        ListBox1.Height = listBoxHeight

        Dim buttonSpacing As Integer = 10
        Me.Height = ButtonOK.Height + 2 * buttonSpacing + ListBox1.Height + 50
    End Sub
    

Eventhandler für die Listbox und die Schaltflächen

Die Eventhandler legen fest, was bei Benutzerinteraktion passieren soll. Wenn ein Element in der Liste ausgewählt wird, wird der Index und das Element gespeichert und die OK-Schaltfläche aktiviert. Wenn die OK-Schaltfläche gedrückt wird, wird der Dialog geschlossen und DialogResult auf OK gesetzt. Wenn die Abbruch-Schaltfläche gedrückt wird, wird DialogResult auf Cancel gesetzt und der Dialog geschlossen.

Außerdem wird eine Enumeration Auswertungsart definiert, die es ermöglicht, die Auswertungsart einfach festzulegen. Danach endet die Klasse.

      Private Sub ListBox_SelectedIndexChanged(sender As Object, e As EventArgs)
        SelectedIndex = ListBox1.SelectedIndex
        SelectedItem = CType(Items(SelectedIndex),T)
        ButtonOK.Enabled = (SelectedIndex >= 0)
    End Sub
    Private Sub ButtonOK_Click(sender As Object, e As EventArgs)
        Me.DialogResult = DialogResult.OK
        Me.Close()
    End Sub
    Private Sub ButtonCancel_Click(sender As Object, e As EventArgs)
        Me.DialogResult = DialogResult.Cancel
        Me.SelectedIndex = -1
        Me.Close()
    End Sub

    Private Enum Auswertungsart
        AuswertungNichts
        AuswertungString
        AuswertungToString
        AuswertungDisplayName
        AuswertungName
    End Enum
End Class

Der Adapter

Für den Fall, dass die Objekte in der Liste nicht die gewünschten Eigenschaften haben, kann ein Adapter übergeben werden, der die gewünschten Eigenschaften ausliest. Der Adapter muss das Interface IObjektAdapter implementieren und die Methode GetStringArray enthalten, die die Objekte in der Liste und die Anzahl der Elemente übergeben bekommt und ein String-Array zurückgibt. Hier ein einfaches Beispiel für einen Adapter, der aus einem Asset die DisplayName-Eigenschaft ausliest, so wie das auch die AuswahlDialog-Klasse selbst macht. Hier kann man für jede Objektart einen eigenen Adapter schreiben, der die gewünschten Eigenschaften ausliest, falls man für einen Einzelfall nicht den AuswahlDialeg ändern möchte.

Public Interface IObjektAdapter
    Function GetStringArray(items As IEnumerable, anzahl As Integer) As String()
End Interface

Class AssetAdapter
    Implements IObjektAdapter

    Public Function GetStringArray(items As IEnumerable, anzahl As Integer) As String() Implements IObjektAdapter.GetStringArray
        Dim namen(anzahl - 1) As String
        For i As Integer = 0 To anzahl - 1
            namen(i) = CType(items(i), Asset).DisplayName
        Next
        Return namen
    End Function
End Class

Der vollständige Code

Um den AuswahlDialog zu verwenden, muss man die Imports, die AuswahlDialog-Klasse und, falls man den Adapter verwenden möchte, auch das IObjektAdapter-Interface und die passend erzeugte Adapterklasse in die iLogic-Regel kopieren. Wenn der Adapter gar nicht benötigt wird, können das Argument im Konstruktor und die Codezeilen, die den Adapter verwenden, entfernt werden.

Hier ist der vollständige Code, der die Auswahl eines Werkstoffs aus der zweiten Werkstoffbibliothek ermöglicht.

    
Imports System.Windows.Forms
Imports System.Reflection

Sub Main()
    Dim invApp As Inventor.Application = ThisApplication
    Dim width As Integer = invApp.Width
    Dim height As Integer = invApp.Height
    Dim links As Integer = invApp.Left
    Dim oben As Integer = invApp.Top
    Dim fenstermitte As Point2d = invApp.TransientGeometry.CreatePoint2d(links + width \ 2, oben + height \ 2)
	
    Dim werkstoffauswahlDialog As New AuswahlDialog(Of Asset)(invApp.AssetLibraries(2).MaterialAssets)
    werkstoffauswahlDialog.Text = "Werkstoff auswählen"
    werkstoffauswahlDialog.ButtonOK.Text = "Auswählen"
    werkstoffauswahlDialog.AdjustWindowHeight(height)
    werkstoffauswahlDialog.SetPos(fenstermitte.X - werkstoffauswahlDialog.Width \ 2, fenstermitte.Y - werkstoffauswahlDialog.Height \ 2)

    Dim werkstoff As Asset = Nothing
    Dim antwort As DialogResult = werkstoffauswahlDialog.ShowDialog()
    If antwort = DialogResult.OK Then
        werkstoff = werkstoffauswahlDialog.SelectedItem
    End If
    If werkstoff IsNot Nothing Then
        Logger.Info(werkstoff.DisplayName & " ausgewählt.")
    Else
        Logger.Info("Kein Werkstoff ausgewählt.")
        Exit Sub
    End If
End Sub


Public Class AuswahlDialog(Of T)
    Inherits Form

    Private ReadOnly ListBox1 As New ListBox()
    Friend ButtonOK As New Button()
    Friend ButtonCancel As New Button()

    Public Property SelectedIndex As Integer
    Public Property SelectedItem As T
    Private Property Adapter As IObjektAdapter
    Private Property Items As IEnumerable

    Public Sub New(items As IEnumerable, Optional adapter As IObjektAdapter = Nothing, Optional startIndex As Integer = -1)
        Dim anzahl As Integer = 0
        Dim listTypeInfo As Type = items.GetType()
        Dim prop As System.Reflection.PropertyInfo
        prop = listTypeInfo.GetProperty("Length")
        If prop Is Nothing Then
            prop = listTypeInfo.GetProperty("Count")
        End If
        If prop IsNot Nothing Then
            anzahl = prop.GetValue(items)
        Else
            Dim met As System.Reflection.MethodInfo
            met = listTypeInfo.GetMethod("Count")

            If met IsNot Nothing Then
                anzahl = listTypeInfo.GetMethod("Count").Invoke(items, Nothing)
                anzahl = met.Invoke(items, Nothing)
            Else
                'Wenn nichts funktioniert, einfach durchzählen
                For Each item As Object In items
                    anzahl += 1
                Next
            End If
        End If


        Dim auswertung As Auswertungsart = Auswertungsart.AuswertungNichts
        Me.Items = items
        'Wenn adapter Nothing ist, wird die Standardauswertung versucht
        If adapter Is Nothing Then
            Dim typeInfo As Type = Nothing

            If typeInfo Is Nothing Then
                typeInfo = GetType(T)
            End If

            If typeInfo Is GetType(String) Then
                auswertung = Auswertungsart.AuswertungString
            ElseIf typeInfo.GetProperty("DisplayName") IsNot Nothing Or typeInfo.GetMethod("DisplayName") IsNot Nothing Then
                auswertung = Auswertungsart.AuswertungDisplayName
            ElseIf typeInfo.GetProperty("Name") IsNot Nothing Then
                auswertung = Auswertungsart.AuswertungName
            ElseIf typeInfo.GetMethod("ToString") IsNot Nothing Then
                auswertung = Auswertungsart.AuswertungToString
            End If

            ' versuche, die Auswertung durch Ausprobieren zu finden
            If auswertung = Auswertungsart.AuswertungNichts Then
                Dim test As String
                Try
                    test = Me.Items(0).DisplayName
                    auswertung = Auswertungsart.AuswertungDisplayName
                Catch
                    Try
                        test = Me.Items(0).Name
                        auswertung = Auswertungsart.AuswertungName
                    Catch
                    End Try
                End Try
            End If
        Else
            Me.Adapter = adapter
        End If
        ' Form-Einstellungen
        Me.Text = "Auswahl treffen"
        Me.Width = 320
        Me.Height = 300

        Me.StartPosition = FormStartPosition.CenterScreen

        ' ListBox hinzufügen
        ' Wenn wir einen adapter haben, verwenden wir diesen
        If Me.Adapter IsNot Nothing Then
            ListBox1.Items.AddRange(Me.Adapter.GetStringArray(Me.Items, anzahl))
        Else
            For i As Integer = 0 To anzahl - 1
                Select Case auswertung
                    Case Auswertungsart.AuswertungString
                        ListBox1.Items.Add(CType(items(i), String))
                    Case Auswertungsart.AuswertungDisplayName
                        ListBox1.Items.Add(items(i).DisplayName)
                    Case Auswertungsart.AuswertungName
                        ListBox1.Items.Add(items(i).Name)
                    Case Auswertungsart.AuswertungToString
                        ListBox1.Items.Add(items(i).ToString())
                    Case Else
                        ListBox1.Items.Add("keine passende Auswertungsart gefunden")
                End Select
            Next
        End If
        ListBox1.Dock = DockStyle.Top
        AddHandler ListBox1.SelectedIndexChanged, AddressOf ListBox_SelectedIndexChanged
        Me.Controls.Add(ListBox1)

        ' Panel für Buttons
        Dim panel As New FlowLayoutPanel()
        panel.FlowDirection = FlowDirection.RightToLeft
        panel.Dock = DockStyle.Bottom
        panel.Height = 40

        ' OK-Button
        ButtonOK.Text = "OK"
        ButtonOK.Enabled = False
        AddHandler ButtonOK.Click, AddressOf ButtonOK_Click
        panel.Controls.Add(ButtonOK)

        If startIndex < anzahl - 1 Then
            Me.SelectedIndex = startIndex
        Else
            Me.SelectedIndex = -1
        End If

        If Me.SelectedIndex > -1 Then 
            ListBox1.SelectedIndex = startIndex
            Me.SelectedItem = CType(Me.Items(startIndex),T)
        End If

        ' Cancel-Button
        ButtonCancel.Text = "Abbrechen"
        AddHandler ButtonCancel.Click, AddressOf ButtonCancel_Click
        panel.Controls.Add(ButtonCancel)

        Me.Controls.Add(panel)
        Me.MaximizeBox = False
        Me.MinimizeBox = False
        Me.AutoSize = True
        Me.AdjustWindowHeight()
    End Sub

    Public Sub SetPos(links As Integer, oben As Integer)
        Me.StartPosition = FormStartPosition.Manual
        Me.Left = links
        Me.Top = oben
    End Sub

    Public Sub AdjustWindowHeight(Optional maxHoehe As Integer = 1000)

        ' Bildschirmhöhe übernehmen
        Dim screenHeight As Integer = maxHoehe

        ' Maximale Höhe der listBox (halbe Bildschirmhöhe)
        Dim maxlistBoxHeight As Integer = screenHeight \ 2

        ' Berechnung der listBox-Höhe basierend auf den Einträgen
        Dim listBoxHeight As Integer = Math.Min(ListBox1.ItemHeight * ListBox1.Items.Count + 30, maxlistBoxHeight)

        ' Höhe der listBox setzen
        ListBox1.Height = listBoxHeight

        ' Fensterhöhe anpassen (inkl. Puffer für Ränder)
        Dim buttonSpacing As Integer = 10
        Me.Height = ButtonOK.Height + 2 * buttonSpacing + ListBox1.Height + 50
    End Sub

    Private Sub ListBox_SelectedIndexChanged(sender As Object, e As EventArgs)
        SelectedIndex = ListBox1.SelectedIndex
        SelectedItem = CType(Items(SelectedIndex), T)
        ButtonOK.Enabled = (SelectedIndex >= 0)
    End Sub
    Private Sub ButtonOK_Click(sender As Object, e As EventArgs)
        Me.DialogResult = DialogResult.OK
        Me.Close()
    End Sub
    Private Sub ButtonCancel_Click(sender As Object, e As EventArgs)
        Me.DialogResult = DialogResult.Cancel
        Me.SelectedIndex = -1
        Me.Close()
    End Sub

    'Enumerator der Auswertungsarten
    Private Enum Auswertungsart
        AuswertungNichts
        AuswertungString
        AuswertungToString
        AuswertungDisplayName
        AuswertungName
    End Enum
End Class

Public Interface IObjektAdapter
    Function GetStringArray(items As IEnumerable, anzahl As Integer) As String()
End Interface

Class AssetAdapter
    Implements IObjektAdapter

    Public Function GetStringArray(items As IEnumerable, anzahl As Integer) As String() Implements IObjektAdapter.GetStringArray
        Dim namen(anzahl - 1) As String
        For i As Integer = 0 To anzahl - 1
            namen(i) = CType(items(i), Asset).DisplayName
        Next
        Return namen
    End Function
End Class

Falls Sie tiefergehende Beratung zu CAD-Methoden benötigen, klicken Sie bitte auf Kontakt.

Links anklicken um in die Zwischenablage kopieren:
Diese Seite: https://r-kon.de/cad-auswahldialog.php
Das Video: https://youtu.be/y739jWsr_fg (Youtube) / https://dai.ly/k4ssNpTHZtJkEhCvKHW (DailyMotion)

← 15: Vorausschauender Modellaufbau
Impressum & Datenschutz X