Code für's Befüllen der ListBox elegant zusammenfassen

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

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

    Code für's Befüllen der ListBox elegant zusammenfassen

    Hi,
    mit diesem Stückchen Code befülle ich meine ListBox.
    Erstens finde ich, es sieht so schon nicht schön aus, und zweitens brauche ich ein If/Else, da ich auf die Länge der Überschrift Acht geben muss und ich daher verschieden viele TABs einbaue. Lässt dich da etwas machen, vielleicht mit LINQ?
    Schön wäre es, wenn ich nicht die
    magische Zahl 20 einbauen müsste.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ' Für jeden Post im ausgewählten Thread
    2. For Each Posting As Class_Post In Liste_mit_allen_Threads(SI).Posts_in_diesem_Thread
    3. ' ListBox befüllen (mit verschieden vielen Tabs)
    4. If Posting.Ueberschrift.Length < 20 Then
    5. ListBox1.Items.Add(
    6. Posting.Ueberschrift & Tab & Tab & Tab & Tab &
    7. Posting.Nummer.ToString(Deu).PadLeft(2, "0"c) & Tab &
    8. Posting.Erstelldatum_dieses_Posts.ToString("g", Deu) & Tab &
    9. Posting.Text_dazu & Tab &
    10. Posting.Made_by.AngezeigterName)
    11. Else
    12. ListBox1.Items.Add(
    13. Posting.Ueberschrift & Tab & Tab &
    14. Posting.Nummer.ToString(Deu).PadLeft(2, "0"c) & Tab &
    15. Posting.Erstelldatum_dieses_Posts.ToString("g", Deu) & Tab &
    16. Posting.Text_dazu & Tab &
    17. Posting.Made_by.AngezeigterName)
    18. End If
    19. '....
    20. Next


    @Bartosz Wie wäre es mit einer DataTable und einem DataGridView?
    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!
    Man kann in der Posting die ToString() Methode überschreiben und dort dann den Text der angezeigt werden soll zusammen setzen. Dann reicht ListBox1.Items.Add(Posting)

    Oder eben in einem DataGrid Anzeigen. Da kann man auch eine List (Of T) als Datenquelle reinhängen, die Properties werden dann als Spalten dargestellt.

    Bei beiden Varianten kann man dann praktischerweise aus dem ListBoxItem bzw. der DataRow wieder ein „Posting“ parsen.
    "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
    Vielleicht auch einen Blick hier rein schauen.

    Um die reale Textlänge auszurechnen, ist die Methode MeasureString manchmal noch ganz nützlich.
    docs.microsoft.com/en-us/dotne…ng.graphics.measurestring

    VB.NET-Quellcode

    1. ​Private Function StringMeasure(str As String, font As Font) As SizeF
    2. Using g = Me.CreateGraphics
    3. Return g.MeasureString(str, font)
    4. End Using
    5. End Function



    Ob das bei dir jetzt sinnvoll ist, kann nicht aus deinem Post heraus gelesen werden.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    Ich würde ein Typisiertes Dataset bevorzugen, RodFromGermany erwähnte ja schon was in dieser Richtung. Sonst wie mrMo schon sagte ToString() Überschreiben, oder eine spezielle function dafür machen.

    VB.NET-Quellcode

    1. Public Function ToStringForListBox(Optional maximumUeberschriftLaenge As Integer = 20) As String
    2. Dim multiTab As String =
    3. If(
    4. Ueberschrift.Length < maximumUeberschriftLaenge,
    5. ControlChars.Tab & ControlChars.Tab & ControlChars.Tab & ControlChars.Tab,
    6. ControlChars.Tab & ControlChars.Tab
    7. )
    8. Return String.Format("{2}{1}{3}{0}{4}{0}{5}{0}{5}", ControlChars.Tab, multiTab, Ueberschrift, Nummer.ToString("00"), Erstelldatum_dieses_Posts.ToString("g", Deu), Text_dazu, Made_by.AngezeigterName)
    9. End Function


    Aber mach am besten mit Dataset und Binding. Hat viele Vorteile.
    Ich fang mal hinten an.
    Vielen Dank, Takafusa, diese String.Format-Sache kannte ich in dieser Tragweite noch nicht. Deine Funktion habe ich nun eingebaut.
    :)
    Copy & Paste Bremse? Da muss eine 6 stehen.

    VB.NET-Quellcode

    1. Return String.Format("{2}{1}{3}{0}{4}{0}{5}{0}{6}",....


    Danke, @exc-jdbi, schau ich mir an.

    Was Typisiertes Dataset, DataGrid(View) und DataTable angeht, damit kenne ich mich nicht aus. Damit muss ich mich beschäftigen.

    Btw: Braucht man kein PadLeft(2, "0"c) mehr? Ich denke, ich bin mir nicht der Mächtigkeit der .ToString("")-Methode bewusst.
    Siehe wegen Zahlen(allgemein) .ToString() mal das hier durch
    docs.microsoft.com/de-de/dotne…rd-numeric-format-strings

    Ich habe es so gemacht Nummer.ToString("00")
    in der Doku ist das gleiche mit ToString("D2") anstatt "00"

    Also sobald es um Daten speichern/laden/bearbeiten geht, lohnt sich unter .Net das Typisierte Dataset, such mal nach den Posts vom ErfinderDesrades zum Thema. Titel wie "DatasetOnly", "Die vier Views auf Video" habe ich da in Erinnerung ich denke das ist ein guter Anfang.
    String.Format kann auch gleich zu nem interpolierten String umgeschrieben werden, macht die Sache einfacher:

    VB.NET-Quellcode

    1. String.Format("{2}{1}{3}{0}{4}{0}{5}{0}{5}", ControlChars.Tab, multiTab, Ueberschrift, Nummer.ToString("00"), Erstelldatum_dieses_Posts.ToString("g", Deu), Text_dazu, Made_by.AngezeigterName)
    ->

    VB.NET-Quellcode

    1. Dim Tab = ControlChars.Tab
    2. Return "{Ueberschrift}{multiTab}{Nummer.ToString("00")}{Tab}{Erstelldatum_dieses_Posts.ToString("g", Deu)}{Tab}{Text_dazu}{Tab}{Made_by.AngezeigterName}"
    Und dann macht VS weitere Vorschläge für Vereinfachungen …
    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.

    Die lange ListBox und seine ItemTemplate, mit einem Objekt-Typ und seine textuelle Darstellung im Kontext von Objekteigenschaften.

    Hi @Bartosz

    Ich hoffe es ist WPF was im Einsatz ist. Wenn nicht, vergiss den folgenden Text... :(

    Ich liebe ListBoxen, im Gegensatz zu @RodFromGermany der ist DataGridView-Driven, ich also ListBox-Driven. (HDGDL Rod)

    Es gibt die Möglichkeit für jedes Item eine Template in der ListBox anzugeben.

    Ich habe ein WPF-Projekt zusammen gedengelt.

    Hier eine Klasse für die Posts.

    VB.NET-Quellcode

    1. Public Class Class_Posting
    2. Public Property Ueberschrift As String
    3. Public Property Made_by As String
    4. Public Property Erstelldatum_dieses_Posts As Date
    5. Public Property Nummer As Integer
    6. End Class


    Beachten Sie bitte hier, das unterschiedliche Datentypen in der Klasse als Eigenschaften vorliegen. :)

    Ich zeige später wie diese dann formatiert werden können und das in XAML.

    Hier die MainWindow Klasse

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Public Class MainWindow
    3. Public Property PostingsListe As New ObservableCollection(Of Class_Posting)
    4. Public Sub New()
    5. ' Dieser Aufruf ist für den Designer erforderlich.
    6. InitializeComponent()
    7. ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
    8. DataContext = Me ' <<<--- Voll Wichtig!
    9. 'Beispieldaten generieren und der Sammlung hinzufügen
    10. For i = 0 To 10
    11. PostingsListe.Add(New Class_Posting With {.Made_by = "Joshi", .Nummer = i, .Ueberschrift = "Titel " & i, .Erstelldatum_dieses_Posts = Now})
    12. Next
    13. End Sub
    14. End Class


    Hier nun das XAML des MainWindow.

    XML-Quellcode

    1. <Window
    2. x:Class="MainWindow"
    3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. xmlns:local="clr-namespace:ItemTemplate_in_ListBox_mit_Run_für_Text"
    7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    8. Title="ItemTemplate in ListBox mit Run für Text"
    9. Width="800"
    10. Height="450"
    11. mc:Ignorable="d">
    12. <Window.Resources>
    13. <DataTemplate x:Key="PostItemTemplate" DataType="local:Class_Posting">
    14. <Grid Margin="5">
    15. <TextBlock>
    16. <Run
    17. FontSize="16"
    18. FontWeight="Bold"
    19. Text="{Binding Ueberschrift, StringFormat={}Topic: {0}}" />
    20. <LineBreak />
    21. <Run Text="{Binding Erstelldatum_dieses_Posts, StringFormat=D, ConverterCulture=de-DE}" />
    22. <Run
    23. FontSize="14"
    24. FontStyle="Italic"
    25. FontWeight="Light"
    26. Foreground="Blue"
    27. Text="{Binding Made_by}" />
    28. <Run Text="{Binding Nummer, StringFormat={}# {0}}" />
    29. </TextBlock>
    30. </Grid>
    31. </DataTemplate>
    32. <Style TargetType="ListBoxItem">
    33. <Style.Triggers>
    34. <Trigger Property="ItemsControl.AlternationIndex" Value="0">
    35. <Setter Property="Background" Value="LightGray" />
    36. </Trigger>
    37. <Trigger Property="ItemsControl.AlternationIndex" Value="1">
    38. <Setter Property="Background" Value="LightBlue" />
    39. </Trigger>
    40. </Style.Triggers>
    41. </Style>
    42. </Window.Resources>
    43. <Grid>
    44. <ListBox
    45. AlternationCount="2"
    46. ItemTemplate="{DynamicResource PostItemTemplate}"
    47. ItemsSource="{Binding PostingsListe, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    48. </Grid>
    49. </Window>


    Ein Screenshot der ListBox. (Hübsch ist was anderes... :/)


    Folgend etwas an Details zur Anwendung.

    Wichtig ist vorher sich eine ItemTemplate zu erstellen.

    Die Dokumentengliederung listet ja alle Elemente im XAML auf, dort auf die ListBox deiner wahl und rechte Maustaste,
    dann "Zusätzliche Vorlagen bearbeiten" -> "Generierte Elemente bearbeiten (ItemTemplate)".

    Dem Ding einen Namen geben, in diesem Beispiel "PostItemTemplate", und es wurde "Leere Vorlage" gewählt und dazu "Definieren in -> Dokument".

    Visual Studio macht dann (falls nicht Vorhanden einen neuen XAML-Knoten auf für "Windows.Resources", und generiert dort die ItemTemplate.

    Diese ist eigentlich eine DataTemplate und bekommt mit dem Namen einen Key, dieser wird dann in der ListBox für die ItemTemplate angegeben.

    Dort ist zunächst nur ein Grid drin und dieses können wir dann frei Gestalten, sogar ersetzen.

    WICHTIG! Erstmal Kaffee, dann das setzen des DatenTyps in der DataTemplate.

    XML-Quellcode

    1. <DataTemplate x:Key="PostItemTemplate" DataType="local:Class_Posting">


    local: Bezieht sich auf ein XMLNS das im Kopf des XAML steht.
    Class_Posting ist dann der DatenTyp (DataType) und schon kann dir der Designer die Eigenschaften mittels IntelliSense anzeigen.

    Jetzt weis die DataTemplate was für Daten er/sie/es/diverse darstellen soll.

    Im Beispiel ist das Grid nur mit einem TextBlock bestückt, was nicht das einzige mittel der Gestaltung sein muss.

    Ein TextBlock kann seine "Text"-Eigenschaft mit "Text-Runs" versehen.

    Das ist der Zweck dieses Posts. Überhaupt und so...

    XML-Quellcode

    1. <Run
    2. FontSize="16"
    3. FontWeight="Bold"
    4. Text="{Binding Ueberschrift, StringFormat={}Topic: {0}}" />


    Das kann als ein "Wort/Zeichen" in der TextBlock.Text-Eigenschaft angesehen werden. (Ohne Gewähr)




    Text="{Binding Ueberschrift, StringFormat={}Topic: {0}}" />

    Hiermit wir das Binding auf eine Eigenschaft (Ueberschrift) in der angegebenen Klasse/DataType gesetzt.

    Text="{Binding , StringFormat={}Topic: {0}}" />

    Ist das selbe als wenn .ToString() ausgerufen würde. (Also das Ergebnis aus Return $"{Ueberschrift}{multiTab}{....)

    StringFormat im Binding.

    Quellcode

    1. , StringFormat={}Topic: {0}}
    2. ^ ^^\_____/ ^
    3. | || | |
    4. | müssen sein | Das ist der Eingabe-Text für das Muster (Hier der Wert aus dem Binding)
    5. | Gibt einen Text vor dem Inhalt an
    6. | Textformatierung mittels Muster


    Ein paar Varianten den Datentyp "Date" zu formatieren.

    XML-Quellcode

    1. <Run Text="{Binding Erstelldatum_dieses_Posts, StringFormat=D, ConverterCulture=de-DE}" />

    XML-Quellcode

    1. <Run Text="{Binding Erstelldatum_dieses_Posts, StringFormat=d, ConverterCulture=de-DE}" />

    XML-Quellcode

    1. <Run Text="{Binding Erstelldatum_dieses_Posts, StringFormat=dd. MMMM, ConverterCulture=de-DE}" />


    Cool, das sogar die Spracheeinstellung mit angegeben werden kann.


    Es sollte so sein wie beim Outsourcing, lass das den XAMLer machen. Ja, der XAMLer der mit dem Huber verheiratet ist... lol

    Was damit gemeint ist, das XAML das formatieren auch übernehmen kann.

    Ich hoffe es hilft etwas...

    c.u. Joshi aus HH

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

    Die ObservableCollection würde ich im ViewModel (konkret im WorkerViewModel) zusammendengeln. Codebehind ist hier gar nicht notwendig.

    Es ist ja auch kein ViewModel vorhanden.

    Apropos ViewModels.

    Es kann sogar statt einer Grid in der DataTemplate/ItemTemplate ja ein View und das dazugehörige ViewModel verwendet werden.

    Somit kann direkt in der ListBox und respektive den einzelnen Einträgen,
    eine eigenständige Funktion mit gegeben werden.
    Wie zum Beispiel CheckBoxen oder ToggleButtons, die an eine Boolean-Eigenschaft gebunden sind, und das nur im ListBoxItem.

    Somit ist es möglich "MikroProgramme" in der ListBox zu vorzuhalten und es kann (etvl.) auf ein Master-Detail verzichtet werden.

    @Dksksm: WorkerViewModel habe ich noch nie gehört, was ist das? Ist es gewerkschaftlich Organisiert? :thumbsup:
    Im Ernst meint es das was ich als "MikroProgramm" bezeichnet habe?

    c.u. Joshi
    Jo, es erbt vom ViewModelBase (BasisKlasse), wo nur die allernötigsten Methoden untergebracht sind.
    Das ist aus früheren WPF-Anfragen aus @Nofear23m's Antworten, seine Beispiele sind eben stark und gut strukturiert, habe ich so nach C# für mich übernommen und komme mit dem Gerüst bestens klar.

    /// <summary> /// Basisklasse für alle ViewModel-Klassen, jede ViewModel-Klasse sollte von dieser Basisklasse erben. /// Implementiert INotifyPropertyChanged, IDataErrorInfo und IValidationInfo /// </summary>
    Hallo @Joshi, vielen Dank für deine Ausführung. Das muss ich mir in Ruhe anschauen. Nein, ich benutze nicht WPF. Ich werde allerdings ein Beispiel-Projekt aufsetzen. Das mach ich auf jeden Fall, denn dein Screenshot sieht besser aus als meine Standard-Listbox. Ich dachte eigentlich, ich habe das erreicht, was die Listox kann (und ja, ich kenne "Keine Strings in die File-ListBox", aber das hat damit auch nix zutun).
    Jo, Wpf ist was ganz anderes als WinForms.
    WinForm-Listbox kann nur eine Spalte/Property anzeigen.
    Deine Übungen mit eingebastelten Tabs deuten darauf hin, dass du eiglich besser ein mehrspaltiges Control verwenden solltest - DGV - sagte man dir ja schon.

    Wpf-Listbox ist nicht auf eine Spalte/Property beschränkt. Also die Wpf-Listbox ist einem Winforms-DGV ähnlicher als einer WinForms-Listbox. Im grunde ist sie dem WinForms-DataRepeater noch am ähnlichsten.
    Also ist ganz was anderes, als was du dir unter Listbox vorstellst, wenn du in WinForms aufgewachsen bist.