Dynamische Combobox

  • VB.NET

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Dynamische Combobox

    Tach auch,

    ich habe eine Combobox die dynamisch gefüllt werden muss. Bisher habe ich das.
    Wie jedoch bringe ich die zweite Spalte da rein? Die Combobox soll zwei Spalten haben.

    VB.NET-Quellcode

    1. Dim myReader As MySqlDataReader
    2. Dim mySelectQuery As String = "SELECT Auftragszustand, Info FROM tblAuftrag ORDER BY Auswahl;"
    3. Dim myCommand As New MySqlCommand(mySelectQuery, objConn)
    4. objConn.Open()
    5. myReader = myCommand.ExecuteReader()
    6. While myReader.Read()
    7. combAuftrag.Items.Add(myReader.GetString(0) & " und das als 2te Zeile --> " & myReader.GetString(1))
    8. End While
    9. myReader.Close()
    10. objConn.Close()
    Mit freundlichen Dinges

    Lupus
    P.S: bei allen meine Fragen beziehen sich auf das arbeiten mit Visual Studio 2019 auf Win 10/64 bit und MySQL

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Lupusverlach“ () aus folgendem Grund: Habe Zeile geschrieben, sollte Spalte aber lauten :(

    falls du meinst, du möchtest das nicht in einer Zeile, sondern mit Hilfe eines Zeilenumbruchs haben, dann nutze Steuerzeichen wie ​Environment.NewLine

    also:

    VB.NET-Quellcode

    1. combAuftrag.Items.Add(myReader.GetString(0) & Environment.NewLine & myReader.GetString(1))


    oder ich habe die Frage falsch verstanden
    Sorry ihr Lieben ... mein Fehler,

    ich meinte Spalte, nicht Zeile, Spalte. Die Combobox sollte zwei Spalten haben.
    Mit freundlichen Dinges

    Lupus
    P.S: bei allen meine Fragen beziehen sich auf das arbeiten mit Visual Studio 2019 auf Win 10/64 bit und MySQL
    Na ja, wenn man mit WPF unterwegs ist, könnte man die Anzeige auch über ein Template überschreiben. und einfach im Style zwei TextBlock Elemente nutzen.

    Mit WinForms müsste man das schon selbst programmieren. Z.B. Indem man von ComboBox ableitet und in der Anzeige ein Control reinschraubt, das zwei Spalten besitzt (oder man schraubt auch diese zusammen)

    Durch Interop wäre es auch möglich eine CustomComboBox mittels WPF zu erstellen und dennoch in WinForms zu nutzen. erschiene mir persönlich nun auch als einfachster Weg.

    VB1963 schrieb:

    Die Combobox hat nur eine Spalte --> da müsstest du dir eine eigene mehrspaltige Combobox programmieren - oder nimm dazu die Listbox oder noch besser --> ein DatagridView ...


    Des macht misch jetzt awwer ferddisch .... ;(
    Vom Platz her und vom Layout passt da nur eine Combobox.
    Gibt es da Beispiele wie man die Programmiert? Habe nun Google gefragt, aber die Tante will mir auch nicht alles verraten :(
    Mit freundlichen Dinges

    Lupus
    P.S: bei allen meine Fragen beziehen sich auf das arbeiten mit Visual Studio 2019 auf Win 10/64 bit und MySQL

    Lupusverlach schrieb:

    Des macht misch jetzt awwer ferddisch
    würde es denn nicht ausreichen, wenn die Combo nur die Info anzeigt?
    Den Auftragszustand kann man in einem beigeordneten Label anzeigen, wenn die Combo das Element gewählt hat.
    Weil eine mehrspaltige Combo selbst zu proggen ist bisserl aufwändiger.
    Wie etwa soll die Breite der Spalten bestimmt werden? Soll das DropDown immer so breit sein wie das breiteste Element beider Spalten zusammen? Andernfalls müsste ja was vom Text abgeschnitten werden.
    Oder eben, ähnlich wie @PadreSperanza bereits vorschlug, "schummeln". Z.B. indem man die Daten in ne passende Datenklasse stopft und mit DataBinding arbeitet. Dann kann man die ComboBox an eben jene Daten via BindingSource binden und in der ComboBox den DisplayMember der ComboBox auf eine zusammengesetzte ReadOnly-Property anbinden.

    VB.NET-Quellcode

    1. Friend Class Order
    2. Property CustomerName As String
    3. Property State As String
    4. ReadOnly Property CustomerStateText As String
    5. Get
    6. Return 'hier Darstellung einbauen
    7. End Get
    8. End Property
    9. End Class

    Beispielergebnisse im Anhang. Das zweite Bild läuft mit StringPadding, aber natürlich nur "schön" mit Monospace-Fonts.
    Bilder
    • ComboBox.png

      3,3 kB, 323×97, 182 mal angesehen
    • ComboBox2.png

      3,69 kB, 510×86, 164 mal angesehen
    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.
    Ich hab mal eine "einfache Art" gebaut, wie man das realisieren kann mittels WPF. Es ist nur ein kleiner, schneller Entwurf - das heißt, Vorteile wie DataBinding, etc. habe ich mal außen vor gelassen, aber so könnte man es bauen (siehe Screenshot).

    Da du mit WinForms arbeitest, musst du erst die Verweise hinzufügen, da du nun mittels Interoperabilität arbeiten müsstest. Hierfür musst die die Schritte wie folgt durchführen:

    Step1: Auf dein Projekt klicken und ein neues Element hinzufügen (siehe Bild Step1).
    Step2: Nach WPF filtern und als Namen so etwas wie "BetterBox" eingeben und hinzufügen. Nun wird die WPF, Namespace und Interoperabilität hinzugefügt.
    Step3: Ziehe eine BetterBox auf dein Control, um es hinzuzufügen. Es wird anschließend ein ItemHost-Element erstellt.
    Step4: Benenne dein Host, wie du ihn brauchst (nicht unbedingt notwendig). Danach kannst du loslegen. Das Resultat, das wir durchgehen, sieht dann wie in cbo_1.png aus (siehe Bild)

    DevStep1: Wir bereiten unsere Form so vor, dass alle Daten parat liegen (c# und VB Code sind dabei).
    Als erstes benötigen wir die Daten. diese liegen wahrscheinlich in irgendeiner Art Liste vor. Ich habe einfach eine Collection erstellt und ihr die (Test)Daten hinzugefügt.

    Für Mytext habe ich eine Klasse erzeugt:

    C#-Quellcode

    1. public class MyText : INotifyPropertyChanged
    2. {
    3. private string _linkeSeite;
    4. public string LinkeSeite
    5. {
    6. get { return _linkeSeite; }
    7. set { SetField(ref _linkeSeite, value); }
    8. }
    9. private string _rechteSeite;
    10. public string RechteSeite
    11. {
    12. get { return _rechteSeite; }
    13. set { SetField(ref _rechteSeite, value); }
    14. }
    15. public MyText(string links, string rechts)
    16. {
    17. _rechteSeite = rechts;
    18. _linkeSeite = links;
    19. }


    VB.NET-Quellcode

    1. Public Class MyText
    2. Inherits INotifyPropertyChanged
    3. Private _linkeSeite As String
    4. Public Property LinkeSeite As String
    5. Get
    6. Return _linkeSeite
    7. End Get
    8. Set(ByVal value As String)
    9. SetField(_linkeSeite, value)
    10. End Set
    11. End Property
    12. Private _rechteSeite As String
    13. Public Property RechteSeite As String
    14. Get
    15. Return _rechteSeite
    16. End Get
    17. Set(ByVal value As String)
    18. SetField(_rechteSeite, value)
    19. End Set
    20. End Property
    21. Public Sub New(ByVal links As String, ByVal rechts As String)
    22. _rechteSeite = rechts
    23. _linkeSeite = links
    24. End Sub




    Anschließend erstelle ich eine neue BetterBox (Ja, brauche ich nicht, da der ItemHost bereits eine erstellt, aber wenn ich zum Beispiel param übergeben möchte, kann es durchaus Sinn ergeben, eine andere zu erstellen, die sich gewünschterweise anpasst).
    Dann füge ich dem ItemHost die neue BetterBox hinzu.

    Hiernach gehe ich alle Einträge durch und füge ein neues Element hinzu.

    C#-Quellcode

    1. public Form1()
    2. {
    3. InitializeComponent();
    4. ObservableCollection<MyText> mytext = new ObservableCollection<MyText>();
    5. mytext.Add(new MyText("links a", "rechts a"));
    6. mytext.Add(new MyText("links b", "rechts b"));
    7. mytext.Add(new MyText("links c", "rechts c"));
    8. mytext.Add(new MyText("links d", "rechts d"));
    9. BetterBox better = new BetterBox();
    10. foreach(MyText t in mytext)
    11. {
    12. better.AddMytext(t);
    13. }
    14. elementHost1.Child = better;
    15. }


    VB.NET-Quellcode

    1. Public Sub New()
    2. InitializeComponent()
    3. Dim mytext As ObservableCollection(Of MyText) = New ObservableCollection(Of MyText)()
    4. mytext.Add(New MyText("links a", "rechts a"))
    5. mytext.Add(New MyText("links b", "rechts b"))
    6. mytext.Add(New MyText("links c", "rechts c"))
    7. mytext.Add(New MyText("links d", "rechts d"))
    8. Dim better As BetterBox = New BetterBox()
    9. For Each t As MyText In mytext
    10. better.AddMytext(t)
    11. Next
    12. elementHost1.Child = better
    13. End Sub


    Die BetterBox braucht natürlich ein Aussehen und auch CodeBehind. Nun, letztendlich soll es sich hierbei lediglich um eine ComboBox handeln, also leiten wir hiervon an. weiterhin braucht sie eine Methode, um Elemente hinzuzufügen:

    Code Behind:


    C#-Quellcode

    1. public partial class BetterBox : UserControl
    2. {
    3. public BetterBox()
    4. {
    5. InitializeComponent();
    6. }
    7. public void AddMytext(MyText value)
    8. {
    9. cbo.Items.Add(new BetterBoxItem((MyText)value));
    10. }
    11. }


    VB.NET-Quellcode

    1. Public Partial Class BetterBox
    2. Inherits UserControl
    3. Public Sub New()
    4. InitializeComponent()
    5. End Sub
    6. Public Sub AddMytext(ByVal value As MyText)
    7. cbo.Items.Add(New BetterBoxItem(CType(value, MyText)))
    8. End Sub
    9. End Class


    Und als XAML sieht es dann wie folgt aus:

    XML-Quellcode

    1. <UserControl x:Class="VB_Paradise.BetterBox"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. xmlns:local="clr-namespace:VB_Paradise"
    7. mc:Ignorable="d"
    8. d:DesignHeight="450" d:DesignWidth="800" x:Name="BetterBoxControl">
    9. <ComboBox x:Name="cbo" Grid.IsSharedSizeScope="True">
    10. </ComboBox>
    11. </UserControl>


    Das ist noch sehr unspektakulär, weil wir ja nur die ComboBox brauchen im UserControl. Im UserControl ist also die ComboBox enthalten und sie hat den Namen "cbo" bekommen (siehe x:Name="cbo") Das "Grid.IsSharedSizeScope="True"" ist für das Design verantwortlich, damit alle Einträge gleich ausgerichtet werden (betrifft aber das Grid, das danach kommt)

    Nun haben wir die ComboBox und die Form. Als nächstes brauchen wir nur noch die Items entsprechend anlegen: Hierzu bauen wir ein zweites UserControl und nennen es "BetterBoxItem" und dieses fügen wir mit der Methode "AddMyText" hinzu wie im Code oben ersichtlich. Der Code für das BetterBoxItem ist wie folgt:

    C#-Quellcode

    1. public partial class BetterBoxItem : UserControl
    2. {
    3. public BetterBoxItem()
    4. {
    5. InitializeComponent();
    6. }
    7. public BetterBoxItem(MyText text) :this()
    8. {
    9. this.linkeSeite.Text = text.LinkeSeite;
    10. this.rechteSeite.Text = text.RechteSeite;
    11. }
    12. }


    VB.NET-Quellcode

    1. Public Partial Class BetterBoxItem
    2. Inherits UserControl
    3. Public Sub New()
    4. InitializeComponent()
    5. End Sub
    6. Public Sub New(ByVal text As MyText)
    7. Me.New()
    8. Me.linkeSeite.Text = text.LinkeSeite
    9. Me.rechteSeite.Text = text.RechteSeite
    10. End Sub
    11. End Class


    Im überladenen Konstruktor, der ein MyText-Objekt aufnimmt, fügt den beiden Textboxen (linkeSeite / rechteSeite) jeweils die strings hinzu.

    Der XAML-Aufbau sieht wie folgt aus:

    XML-Quellcode

    1. <UserControl x:Class="VB_Paradise.BetterBoxItem"
    2. xmlns="http:..."
    3. ... d:DesignWidth="800">
    4. <Grid>
    5. <Grid.ColumnDefinitions>
    6. <ColumnDefinition Width="auto" SharedSizeGroup="a"/>
    7. <ColumnDefinition Width="auto" SharedSizeGroup="b"/>
    8. </Grid.ColumnDefinitions>
    9. <TextBlock x:Name="linkeSeite" Margin="0,0,40,0"/>
    10. <TextBlock x:Name="rechteSeite" Grid.Column="1"/>
    11. </Grid>
    12. </UserControl>


    Das BetterBoxItem besteht also zusammen aus einem Grid-Panel, welches zwei TextBoxen beinhaltet. Durch das SharedSizeGroup teilen sich alle die TextBoxen die in Group a sind und jene in Group b die gleiche Width und somit richten sich alle Elemente gleich aus. Da auch TextBoxes mit weniger Text die Länge der größten TextBox annehmen.

    Ich hoffe, das hilft dir weiter.

    LG Padre

    EDIT: cbo_1 sieht nur deshalb so groß aus, weil ich den Host auf die volle Breite des Panels ausgerichtet habe. ist es kleiner, sieht das Verhältnis auch besser aus ;)
    Bilder
    • cbo_1.png

      7,5 kB, 800×263, 151 mal angesehen
    • step1.png

      40,22 kB, 831×342, 154 mal angesehen
    • step2.png

      15,19 kB, 712×643, 153 mal angesehen
    • step3.png

      23,83 kB, 857×360, 151 mal angesehen
    • step4.png

      14,9 kB, 362×341, 146 mal angesehen