<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kategorie: Tutorials - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/category/allgemein/tutorials/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Wed, 08 Apr 2026 22:31:29 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://robbelroot.de/wp-content/uploads/2020/12/cropped-favicon-32x32.png</url>
	<title>Kategorie: Tutorials - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>VB.NET WhatsApp Nachricht senden per Cloud API (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-whatsapp-nachricht-senden/</link>
					<comments>https://robbelroot.de/blog/vbnet-whatsapp-nachricht-senden/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 22:30:59 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20494</guid>

					<description><![CDATA[<p>Du kannst WhatsApp-Nachrichten aus VB.NET senden, indem du die offizielle WhatsApp Cloud API mit einem einfachen HttpClient-Request nutzt. Keine externe Bibliothek nötig. Dieser Guide behandelt Setup, Text-Nachrichten, Template-Nachrichten, API-Antworten, Massenversand und eine Twilio-Alternative mit vollständigen Code-Beispielen. Was du brauchst Bevor du Code schreibst, brauchst du drei Dinge von Meta: Meta &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-whatsapp-nachricht-senden/">VB.NET WhatsApp Nachricht senden per Cloud API (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Du kannst <strong>WhatsApp-Nachrichten aus VB.NET senden</strong>, indem du die offizielle WhatsApp Cloud API mit einem einfachen <code>HttpClient</code>-Request nutzt. Keine externe Bibliothek nötig. Dieser Guide behandelt Setup, Text-Nachrichten, Template-Nachrichten, API-Antworten, Massenversand und eine Twilio-Alternative mit vollständigen Code-Beispielen.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">.NET-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du baust ein Benachrichtigungssystem?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Von WhatsApp-Integrationen bis zur kompletten Desktop-Lösung kann ich helfen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Was du brauchst</h2>



<p>Bevor du Code schreibst, brauchst du drei Dinge von Meta:</p>



<ol class="wp-block-list">
<li><strong>Meta Business Account</strong> mit einer registrierten App auf <a href="https://developers.facebook.com/" target="_blank" rel="noopener">developers.facebook.com</a></li>



<li><strong>Phone Number ID</strong> aus dem WhatsApp-Bereich in deinem App-Dashboard</li>



<li><strong>Access Token</strong> (temporär zum Testen, permanent über System User für Produktion)</li>
</ol>



<p>Meta stellt eine kostenlose Test-Rufnummer und fünf Test-Empfänger bereit. Du kannst während der Entwicklung echte Nachrichten ohne Kosten senden.</p>



<h2 class="wp-block-heading">So funktioniert die WhatsApp Cloud API</h2>



<p>Die WhatsApp Cloud API ist eine REST API, die von Meta gehostet wird. Deine VB.NET-Anwendung sendet einen HTTP-POST-Request mit JSON-Body an Metas Server. Meta liefert die Nachricht dann an die WhatsApp-App des Empfängers. Der Ablauf:</p>



<ol class="wp-block-list">
<li>Deine App sendet einen POST-Request an <code>https://graph.facebook.com/v20.0/{phone_number_id}/messages</code></li>



<li>Meta prüft deinen Token, die Rufnummer und das Nachrichtenformat</li>



<li>Meta stellt die Nachricht über WhatsApp-Server zu</li>



<li>Du erhältst eine JSON-Antwort mit der Nachrichten-ID oder einem Fehler</li>
</ol>



<p>Eine wichtige Regel: Du kannst nur <strong>Template-Nachrichten</strong> an Nutzer senden, die dir in den letzten 24 Stunden nicht geschrieben haben. Freitext-Nachrichten sind nur innerhalb eines 24-Stunden-Gesprächsfensters erlaubt. Für die meisten Benachrichtigungs-Szenarien (Bestellbestätigungen, Alerts, Erinnerungen) sind Template-Nachrichten der richtige Weg.</p>



<h2 class="wp-block-heading">Textnachricht senden</h2>



<p>Das einfachste Beispiel. Es sendet eine Klartext-Nachricht an einen einzelnen Empfänger innerhalb eines aktiven Gesprächsfensters:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports System.Net.Http
Imports System.Text

Private Async Function SendWhatsAppMessage(recipientPhone As String, message As String) As Task(Of Boolean)
    Dim phoneNumberId As String = "YOUR_PHONE_NUMBER_ID"
    Dim accessToken As String = "YOUR_ACCESS_TOKEN"
    Dim url As String = $"https://graph.facebook.com/v20.0/{phoneNumberId}/messages"

    Dim json As String = "{" &amp;
        """messaging_product"": ""whatsapp""," &amp;
        """to"": """ &amp; recipientPhone &amp; """," &amp;
        """type"": ""text""," &amp;
        """text"": {""body"": """ &amp; message &amp; """}" &amp;
        "}"

    Using client As New HttpClient()
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " &amp; accessToken)
        Dim content As New StringContent(json, Encoding.UTF8, "application/json")
        Dim response = Await client.PostAsync(url, content)
        Return response.IsSuccessStatusCode
    End Using
End Function</pre>



<p>Aufruf per Button-Klick oder beliebigem Event-Handler:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private Async Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
    Dim success = Await SendWhatsAppMessage("491234567890", "Deine Bestellung wurde versendet.")

    If success Then
        lblStatus.Text = "Nachricht gesendet."
    Else
        lblStatus.Text = "Nachricht konnte nicht gesendet werden."
    End If
End Sub</pre>



<p>Die Rufnummer muss die Landesvorwahl ohne Pluszeichen oder führende Nullen enthalten. Für eine deutsche Nummer wie +49 123 4567890 verwendest du <code>491234567890</code>.</p>



<h2 class="wp-block-heading">Template-Nachricht senden</h2>



<p>Template-Nachrichten sind vorab genehmigte Nachrichtenformate, die du in deinem Meta Business Dashboard erstellst. Sie sind erforderlich, wenn du die erste Nachricht an einen Nutzer sendest oder außerhalb des 24-Stunden-Fensters kommunizierst:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private Async Function SendTemplateMessage(recipientPhone As String, templateName As String) As Task(Of Boolean)
    Dim phoneNumberId As String = "YOUR_PHONE_NUMBER_ID"
    Dim accessToken As String = "YOUR_ACCESS_TOKEN"
    Dim url As String = $"https://graph.facebook.com/v20.0/{phoneNumberId}/messages"

    Dim json As String = "{" &amp;
        """messaging_product"": ""whatsapp""," &amp;
        """to"": """ &amp; recipientPhone &amp; """," &amp;
        """type"": ""template""," &amp;
        """template"": {" &amp;
            """name"": """ &amp; templateName &amp; """," &amp;
            """language"": {""code"": ""de""}" &amp;
        "}" &amp;
        "}"

    Using client As New HttpClient()
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " &amp; accessToken)
        Dim content As New StringContent(json, Encoding.UTF8, "application/json")
        Dim response = Await client.PostAsync(url, content)
        Return response.IsSuccessStatusCode
    End Using
End Function</pre>



<p>Meta stellt ein Standard-Template namens <code>hello_world</code> zum Testen bereit. Eigene Templates erstellst du im WhatsApp-Manager-Bereich deines Meta Business Dashboards. Templates können Variablen wie <code>{{1}}</code> enthalten, die du beim Senden mit dynamischen Inhalten füllst.</p>



<h2 class="wp-block-heading">Template-Nachricht mit Variablen</h2>



<p>Die meisten echten Templates enthalten Platzhalter für Kundennamen, Bestellnummern oder Termine. So sendest du ein Template mit variablen Parametern:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private Async Function SendOrderConfirmation(phone As String, customerName As String, orderId As String) As Task(Of Boolean)
    Dim phoneNumberId As String = "YOUR_PHONE_NUMBER_ID"
    Dim accessToken As String = "YOUR_ACCESS_TOKEN"
    Dim url As String = $"https://graph.facebook.com/v20.0/{phoneNumberId}/messages"

    ' Template "bestellbestaetigung" mit zwei Body-Parametern
    Dim json As String = "{" &amp;
        """messaging_product"": ""whatsapp""," &amp;
        """to"": """ &amp; phone &amp; """," &amp;
        """type"": ""template""," &amp;
        """template"": {" &amp;
            """name"": ""bestellbestaetigung""," &amp;
            """language"": {""code"": ""de""}," &amp;
            """components"": [{" &amp;
                """type"": ""body""," &amp;
                """parameters"": [" &amp;
                    "{""type"": ""text"", ""text"": """ &amp; customerName &amp; """}," &amp;
                    "{""type"": ""text"", ""text"": """ &amp; orderId &amp; """}" &amp;
                "]" &amp;
            "}]" &amp;
        "}" &amp;
        "}"

    Using client As New HttpClient()
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " &amp; accessToken)
        Dim content As New StringContent(json, Encoding.UTF8, "application/json")
        Dim response = Await client.PostAsync(url, content)
        Return response.IsSuccessStatusCode
    End Using
End Function</pre>



<p>Die Parameter füllen die <code>{{1}}</code>-, <code>{{2}}</code>-Platzhalter in deinem Template der Reihe nach. Stelle sicher, dass die Anzahl der Parameter mit den Erwartungen des Templates übereinstimmt.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du ein fertiges Benachrichtigungssystem?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von WhatsApp-Alerts bis zur kompletten Desktop-App mit Datenbankanbindung. Ich entwerfe Software, die hält. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">API-Antwort auswerten</h2>



<p>Eine erfolgreiche Antwort enthält ein JSON-Objekt mit der Nachrichten-ID. Ein Fehler gibt ein strukturiertes Fehlerobjekt zurück. So liest du beides aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private Async Function SendAndLog(recipientPhone As String, message As String) As Task
    Dim phoneNumberId As String = "YOUR_PHONE_NUMBER_ID"
    Dim accessToken As String = "YOUR_ACCESS_TOKEN"
    Dim url As String = $"https://graph.facebook.com/v20.0/{phoneNumberId}/messages"

    Dim json As String = "{" &amp;
        """messaging_product"": ""whatsapp""," &amp;
        """to"": """ &amp; recipientPhone &amp; """," &amp;
        """type"": ""text""," &amp;
        """text"": {""body"": """ &amp; message &amp; """}" &amp;
        "}"

    Using client As New HttpClient()
        client.DefaultRequestHeaders.Add("Authorization", "Bearer " &amp; accessToken)
        Dim content As New StringContent(json, Encoding.UTF8, "application/json")
        Dim response = Await client.PostAsync(url, content)
        Dim body = Await response.Content.ReadAsStringAsync()

        If response.IsSuccessStatusCode Then
            ' body enthält: {"messaging_product":"whatsapp","contacts":[...],"messages":[{"id":"wamid.xxx"}]}
            Console.WriteLine("Gesendet. Antwort: " &amp; body)
        Else
            ' body enthält: {"error":{"message":"...","type":"...","code":100,...}}
            Console.WriteLine("Fehler " &amp; response.StatusCode.ToString() &amp; ": " &amp; body)
        End If
    End Using
End Function</pre>



<p>Für Produktionsanwendungen speichere die Antwort in einer Log-Datei zum Debuggen. Siehe den <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>VB.NET Textdatei schreiben Guide</strong></a> für Logging-Muster.</p>



<h2 class="wp-block-heading">An mehrere Empfänger senden</h2>



<p>Die WhatsApp API akzeptiert einen Empfänger pro Request. Um an mehrere Nummern zu senden, iterierst du über eine <a href="https://robbelroot.de/blog/vbnet-list/"><strong>VB.NET List</strong></a> von Rufnummern:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private Async Function SendToMultiple(phones As List(Of String), message As String) As Task
    Dim successCount As Integer = 0
    Dim failCount As Integer = 0

    For Each phone In phones
        Dim success = Await SendWhatsAppMessage(phone, message)

        If success Then
            successCount += 1
        Else
            failCount += 1
        End If

        ' Rate-Limit einhalten: max 80 Nachrichten pro Sekunde
        Await Task.Delay(50)
    Next

    Console.WriteLine($"Gesendet: {successCount}, Fehlgeschlagen: {failCount}")
End Function</pre>



<p>Das <code>Task.Delay(50)</code> fügt eine kleine Pause zwischen den Requests ein, um innerhalb des API-Rate-Limits zu bleiben. Bei großen Batches (Tausende von Nachrichten) solltest du die Nachrichten in eine Queue stellen und im Hintergrund verarbeiten.</p>



<h2 class="wp-block-heading">Zugangsdaten sicher speichern</h2>



<p>Schreibe deinen Access Token nie fest in den Quellcode. Für Desktop-Anwendungen speicherst du Zugangsdaten in einer externen Config-Datei oder Umgebungsvariablen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Aus App.config oder Umgebungsvariable lesen
Dim accessToken As String = Environment.GetEnvironmentVariable("WHATSAPP_TOKEN")
Dim phoneNumberId As String = Environment.GetEnvironmentVariable("WHATSAPP_PHONE_ID")

If String.IsNullOrEmpty(accessToken) OrElse String.IsNullOrEmpty(phoneNumberId) Then
    MessageBox.Show("WhatsApp-Zugangsdaten nicht konfiguriert.", "Konfigurationsfehler",
        MessageBoxButtons.OK, MessageBoxIcon.Error)
    Return
End If</pre>



<p>Setze Umgebungsvariablen auf der Maschine, auf der deine App läuft, oder verwende <code>My.Settings</code> mit benutzerbezogenen Einstellungen für Einzelbenutzer-Konfiguration.</p>



<h2 class="wp-block-heading">Twilio als Alternative</h2>



<p>Wenn du ein einfacheres SDK gegenüber rohen HTTP-Requests bevorzugst, bietet Twilio eine WhatsApp-Integration mit einem .NET-NuGet-Paket. Installiere <code>Twilio</code> via NuGet:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports Twilio
Imports Twilio.Rest.Api.V2010.Account

' Einmalig beim App-Start initialisieren
TwilioClient.Init("YOUR_ACCOUNT_SID", "YOUR_AUTH_TOKEN")

' Nachricht senden
Dim msg = MessageResource.Create(
    body:="Deine Bestellung wurde versendet.",
    from:=New Twilio.Types.PhoneNumber("whatsapp:+14155238886"),
    [to]:=New Twilio.Types.PhoneNumber("whatsapp:+491234567890")
)

Console.WriteLine("Message SID: " &amp; msg.Sid)</pre>



<p>Twilio kostet Geld pro Nachricht, übernimmt aber Rate-Limiting, Retries und Zustellverfolgung für dich. Die direkte Meta API ist kostenlos (du zahlst nur für Conversations über das Freitier hinaus), aber du machst alles selbst.</p>



<h2 class="wp-block-heading">Häufige Fehler</h2>



<h3 class="wp-block-heading">Freitext außerhalb des 24-Stunden-Fensters senden</h3>



<p>Die API gibt Fehlercode 131047 zurück, wenn du eine Textnachricht an jemanden sendest, der dir in den letzten 24 Stunden nicht geschrieben hat. Verwende stattdessen eine Template-Nachricht. Template-Nachrichten funktionieren jederzeit und sind der Standard-Ansatz für Benachrichtigungen.</p>



<h3 class="wp-block-heading">Falsches Rufnummernformat</h3>



<p>Die API erwartet die vollständige internationale Nummer ohne Pluszeichen, Leerzeichen oder Bindestriche. <code>491234567890</code> ist korrekt. <code>+49 123 456 7890</code>, <code>01234567890</code> oder <code>0049-123-4567890</code> schlagen fehl. Bereinige alle Formatierung vor dem Senden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim cleanPhone = phone.Replace("+", "").Replace(" ", "").Replace("-", "")</pre>



<h3 class="wp-block-heading">Access Token fest im Code</h3>



<p>Temporäre Tokens laufen nach 24 Stunden ab. Wenn du einen fest einträgst und vergisst ihn zu aktualisieren, hört deine App leise auf zu senden. Verwende für Produktion einen permanenten System-User-Token und speichere ihn in Umgebungsvariablen oder einer sicheren Config-Datei, nie im Quellcode.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, von API-Integrationen bis zur kompletten Desktop-Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-whatsapp-de-1"><strong class="schema-faq-question"><strong>Ist die WhatsApp Business API kostenlos?</strong></strong> <p class="schema-faq-answer">Meta bietet 1.000 kostenlose Service-Conversations pro Monat. Darüber hinaus zahlst du pro Conversation (nicht pro Nachricht). Template-Nachrichten für Benachrichtigungen kosten eine kleine Gebühr pro Conversation, abhängig vom Land. Entwicklung und Tests mit der Sandbox-Nummer sind kostenlos.</p> </div> <div class="schema-faq-section" id="faq-whatsapp-de-2"><strong class="schema-faq-question"><strong>Kann ich WhatsApp-Nachrichten aus VB.NET ohne offizielle API senden?</strong></strong> <p class="schema-faq-answer">Technisch könntest du WhatsApp Web mit Selenium automatisieren, aber das verstößt gegen die WhatsApp-Nutzungsbedingungen und kann zur Sperrung deiner Nummer führen. Die offizielle Cloud API oder ein Anbieter wie Twilio sind die einzigen zuverlässigen und konformen Optionen.</p> </div> <div class="schema-faq-section" id="faq-whatsapp-de-3"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen Textnachricht und Template-Nachricht?</strong></strong> <p class="schema-faq-answer">Eine Textnachricht ist frei formulierter Inhalt, den du nur während eines aktiven 24-Stunden-Gesprächsfensters senden kannst. Eine Template-Nachricht ist ein vorab genehmigtes Format, das in deinem Meta-Dashboard registriert ist und jederzeit gesendet werden kann, auch an Nutzer die dir nicht zuerst geschrieben haben.</p> </div> <div class="schema-faq-section" id="faq-whatsapp-de-4"><strong class="schema-faq-question"><strong>Brauche ich eine spezielle Rufnummer für die WhatsApp API?</strong></strong> <p class="schema-faq-answer">Du brauchst eine Rufnummer, die nicht bereits bei WhatsApp oder der WhatsApp Business App registriert ist. Meta stellt eine kostenlose Testnummer für die Entwicklung bereit. Für Produktion registrierst du eine dedizierte Business-Nummer im Meta Business Dashboard.</p> </div> <div class="schema-faq-section" id="faq-whatsapp-de-5"><strong class="schema-faq-question"><strong>Kann ich auch WhatsApp-Nachrichten in VB.NET empfangen?</strong></strong> <p class="schema-faq-answer">Ja, aber dafür brauchst du einen Webhook. Meta sendet eingehende Nachrichten an einen öffentlichen HTTPS-Endpunkt, den du konfigurierst. Für eine Desktop-VB.NET-App brauchst du eine Server-Komponente (ASP.NET oder eine Cloud-Funktion), die den Webhook empfängt und Nachrichten an deine App weiterleitet.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>WhatsApp-Nachrichten aus VB.NET senden läuft über einen einzigen <code>HttpClient.PostAsync</code>-Aufruf an Metas Cloud API. Verwende Template-Nachrichten für Benachrichtigungen, speichere deinen Token sicher und bereinige Rufnummern vor dem Senden. Für einfachere Integration zu höheren Kosten gibt es Twilio als NuGet-Paket. Zum Loggen von API-Antworten in eine Datei, siehe den <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>VB.NET Textdatei schreiben Guide</strong></a>.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-whatsapp-nachricht-senden/">VB.NET WhatsApp Nachricht senden per Cloud API (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-whatsapp-nachricht-senden/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET MsgBox – Meldungsdialoge einfach erklärt (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-msgbox/</link>
					<comments>https://robbelroot.de/blog/vbnet-msgbox/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 22:15:07 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20487</guid>

					<description><![CDATA[<p>Die VB.NET MsgBox-Funktion zeigt eine Meldung an und gibt zurück, welchen Button der Benutzer geklickt hat. Sie eignet sich für schnelle Hinweise, Bestätigungen und Ja/Nein-Abfragen. Dieser Guide behandelt Syntax, Button-Kombinationen, Icons, Rückgabewerte, den Unterschied zwischen MsgBox und MessageBox.Show und wann du was verwenden solltest. MsgBox vs. MessageBox.Show VB.NET bietet zwei &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-msgbox/">VB.NET MsgBox – Meldungsdialoge einfach erklärt (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Die <strong>VB.NET MsgBox</strong>-Funktion zeigt eine Meldung an und gibt zurück, welchen Button der Benutzer geklickt hat. Sie eignet sich für schnelle Hinweise, Bestätigungen und Ja/Nein-Abfragen. Dieser Guide behandelt Syntax, Button-Kombinationen, Icons, Rückgabewerte, den Unterschied zwischen <code>MsgBox</code> und <code>MessageBox.Show</code> und wann du was verwenden solltest.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">.NET-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du baust eine Desktop-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Von Meldungsdialogen bis zur kompletten WinForms-Anwendung kann ich helfen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">MsgBox vs. MessageBox.Show</h2>



<p>VB.NET bietet zwei Wege, eine Meldung anzuzeigen. Beide öffnen denselben Windows-Dialog, unterscheiden sich aber in Herkunft und API-Stil:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' VB.NET-Stil (aus Microsoft.VisualBasic Namespace)
MsgBox("Datei gespeichert.", MsgBoxStyle.Information, "Erfolg")

' .NET Framework-Stil (aus System.Windows.Forms)
MessageBox.Show("Datei gespeichert.", "Erfolg", MessageBoxButtons.OK, MessageBoxIcon.Information)</pre>



<figure class="wp-block-table"><table><thead><tr><th>Aspekt</th><th>MsgBox</th><th>MessageBox.Show</th></tr></thead><tbody><tr><td>Namespace</td><td><code>Microsoft.VisualBasic</code></td><td><code>System.Windows.Forms</code></td></tr><tr><td>In C# verfügbar</td><td>Nein (nur VB.NET)</td><td>Ja</td></tr><tr><td>Rückgabetyp</td><td><code>MsgBoxResult</code></td><td><code>DialogResult</code></td></tr><tr><td>Button/Icon-Enums</td><td><code>MsgBoxStyle</code> (kombinierbar)</td><td>Getrennte Enums für Buttons und Icons</td></tr><tr><td>Parameter-Reihenfolge</td><td>Nachricht, Stil, Titel</td><td>Nachricht, Titel, Buttons, Icon</td></tr></tbody></table></figure>



<p><code>MsgBox</code> ist ein VB.NET-Wrapper um die Win32-<code>MessageBox</code>-API. <code>MessageBox.Show</code> ist die .NET-Framework-Klasse, die in allen .NET-Sprachen funktioniert. Beide erzeugen exakt dasselbe Dialog-Fenster. Wenn dein Projekt rein VB.NET ist, funktioniert beides. Wenn du Code mit C#-Entwicklern teilst oder .NET-Konventionen folgst, ist <code>MessageBox.Show</code> die bessere Wahl.</p>



<h2 class="wp-block-heading">MsgBox Syntax</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim result As MsgBoxResult = MsgBox(
    Prompt,            ' Der Nachrichtentext (erforderlich)
    Buttons Or Icon,   ' MsgBoxStyle-Flags (optional)
    Title              ' Fenstertitel (optional)
)</pre>



<p>Der erste Parameter ist die Nachricht. Der zweite kombiniert Button- und Icon-Stile mit <code>Or</code>. Der dritte setzt den Fenstertitel. Nur der erste Parameter ist erforderlich.</p>



<h2 class="wp-block-heading">Einfache Meldung</h2>



<p>Die einfachste MsgBox mit nur einer Nachricht und dem Standard-OK-Button:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">MsgBox("Die Datei wurde gespeichert.")</pre>



<p>Mit Titel und Informations-Icon:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">MsgBox("Die Datei wurde gespeichert.", MsgBoxStyle.Information, "Erfolg")</pre>



<h2 class="wp-block-heading">Ja/Nein-Bestätigung</h2>



<p>Dem Benutzer eine Ja/Nein-Frage stellen und auf die Antwort reagieren:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim result = MsgBox(
    "Möchtest du diesen Datensatz löschen?",
    MsgBoxStyle.YesNo Or MsgBoxStyle.Question,
    "Löschen bestätigen")

If result = MsgBoxResult.Yes Then
    DeleteRecord()
End If</pre>



<p>Kombiniere Button-Stil und Icon-Stil mit <code>Or</code>. Der Rückgabewert sagt dir, welcher Button geklickt wurde.</p>



<h2 class="wp-block-heading">Ja/Nein/Abbrechen</h2>



<p>Für ungespeicherte Änderungen drei Optionen anbieten:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim result = MsgBox(
    "Du hast ungespeicherte Änderungen. Vor dem Schließen speichern?",
    MsgBoxStyle.YesNoCancel Or MsgBoxStyle.Exclamation,
    "Ungespeicherte Änderungen")

Select Case result
    Case MsgBoxResult.Yes
        SaveDocument()
        Me.Close()
    Case MsgBoxResult.No
        Me.Close()
    Case MsgBoxResult.Cancel
        ' Nichts tun, auf dem Form bleiben
End Select</pre>



<h2 class="wp-block-heading">Alle Button-Stile</h2>



<figure class="wp-block-table"><table><thead><tr><th>MsgBoxStyle</th><th>Angezeigte Buttons</th><th>Mögliche Ergebnisse</th></tr></thead><tbody><tr><td><code>OKOnly</code> (Standard)</td><td>OK</td><td><code>Ok</code></td></tr><tr><td><code>OKCancel</code></td><td>OK, Abbrechen</td><td><code>Ok</code>, <code>Cancel</code></td></tr><tr><td><code>YesNo</code></td><td>Ja, Nein</td><td><code>Yes</code>, <code>No</code></td></tr><tr><td><code>YesNoCancel</code></td><td>Ja, Nein, Abbrechen</td><td><code>Yes</code>, <code>No</code>, <code>Cancel</code></td></tr><tr><td><code>RetryCancel</code></td><td>Wiederholen, Abbrechen</td><td><code>Retry</code>, <code>Cancel</code></td></tr><tr><td><code>AbortRetryIgnore</code></td><td>Abbrechen, Wiederholen, Ignorieren</td><td><code>Abort</code>, <code>Retry</code>, <code>Ignore</code></td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Alle Icon-Stile</h2>



<figure class="wp-block-table"><table><thead><tr><th>MsgBoxStyle</th><th>Icon</th><th>Einsatz</th></tr></thead><tbody><tr><td><code>Information</code></td><td>Blauer Info-Kreis</td><td>Statusmeldungen, Bestätigungen</td></tr><tr><td><code>Question</code></td><td>Blaues Fragezeichen</td><td>Ja/Nein-Abfragen</td></tr><tr><td><code>Exclamation</code></td><td>Gelbes Warndreieck</td><td>Warnungen, ungespeicherte Änderungen</td></tr><tr><td><code>Critical</code></td><td>Roter Fehlerkreis</td><td>Fehler, kritische Probleme</td></tr></tbody></table></figure>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du eine fertige WinForms-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von Meldungsdialogen bis zur kompletten datengetriebenen Desktop-App: Ich entwerfe Software, die hält. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Standard-Button ändern</h2>



<p>Standardmäßig ist der erste Button fokussiert. Du kannst das ändern, um versehentliche Klicks auf destruktive Aktionen zu vermeiden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' "Nein" standardmäßig fokussieren, damit nicht versehentlich gelöscht wird
Dim result = MsgBox(
    "Alle Datensätze endgültig löschen?",
    MsgBoxStyle.YesNo Or MsgBoxStyle.Critical Or MsgBoxStyle.DefaultButton2,
    "Warnung")

If result = MsgBoxResult.Yes Then
    DeleteAllRecords()
End If</pre>



<p><code>DefaultButton2</code> fokussiert den zweiten Button (Nein). Verwende <code>DefaultButton3</code> für den dritten Button bei Drei-Button-Dialogen.</p>



<h2 class="wp-block-heading">Dieselben Beispiele mit MessageBox.Show</h2>



<p>Hier die gleichen Muster mit der .NET-Variante <code>MessageBox.Show</code> zum Vergleichen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Einfache Meldung
MessageBox.Show("Die Datei wurde gespeichert.", "Erfolg",
    MessageBoxButtons.OK, MessageBoxIcon.Information)

' Ja/Nein-Bestätigung
Dim result As DialogResult = MessageBox.Show(
    "Möchtest du diesen Datensatz löschen?", "Löschen bestätigen",
    MessageBoxButtons.YesNo, MessageBoxIcon.Question)

If result = DialogResult.Yes Then
    DeleteRecord()
End If

' Ja/Nein/Abbrechen mit Standard-Button
Dim result2 As DialogResult = MessageBox.Show(
    "Vor dem Schließen speichern?", "Ungespeicherte Änderungen",
    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning,
    MessageBoxDefaultButton.Button2)

Select Case result2
    Case DialogResult.Yes
        SaveDocument()
        Me.Close()
    Case DialogResult.No
        Me.Close()
    Case DialogResult.Cancel
        ' Auf dem Form bleiben
End Select</pre>



<p>Die Funktion ist identisch. <code>MessageBox.Show</code> verwendet getrennte Enums (<code>MessageBoxButtons</code>, <code>MessageBoxIcon</code>, <code>MessageBoxDefaultButton</code>) statt Flags mit <code>Or</code> zu kombinieren. Der Rückgabetyp ist <code>DialogResult</code> statt <code>MsgBoxResult</code>.</p>



<h2 class="wp-block-heading">Wann was verwenden</h2>



<p>Verwende <code>MsgBox</code>, wenn:</p>



<ul class="wp-block-list">
<li>Dein Projekt <strong>rein VB.NET</strong> ist und du kürzere Syntax bevorzugst</li>



<li>Du <strong>schnell prototypen</strong> willst und minimalen Code brauchst</li>
</ul>



<p>Verwende <code>MessageBox.Show</code>, wenn:</p>



<ul class="wp-block-list">
<li>Deine Codebasis <strong>mit C#-Entwicklern geteilt</strong> wird</li>



<li>Du <strong>.NET-Konventionen</strong> folgen willst</li>



<li>Du den <strong>Owner-Window-Parameter</strong> brauchst (um den Dialog über einem bestimmten Form zu halten)</li>



<li>Dein Code <strong>portierbar</strong> zu .NET 5+ / .NET 8+ Projekten sein soll</li>
</ul>



<h2 class="wp-block-heading">Komplettes Beispiel: Speichern-vor-Schließen-Muster</h2>



<p>Ein realistisches Beispiel, das vor dem Schließen eines Forms zum Speichern auffordert. Dieses Muster funktioniert in jedem Texteditor, Dateneingabe-Form oder Einstellungsfenster:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private _hasChanges As Boolean = False

Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
    _hasChanges = True
End Sub

Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    If Not _hasChanges Then Return

    Dim result = MsgBox(
        "Du hast ungespeicherte Änderungen. Jetzt speichern?",
        MsgBoxStyle.YesNoCancel Or MsgBoxStyle.Exclamation Or MsgBoxStyle.DefaultButton1,
        "Ungespeicherte Änderungen")

    Select Case result
        Case MsgBoxResult.Yes
            SaveToFile()
        Case MsgBoxResult.Cancel
            e.Cancel = True  ' Schließen verhindern
    End Select
End Sub

Private Sub SaveToFile()
    File.WriteAllText("data.txt", TextBox1.Text, Encoding.UTF8)
    _hasChanges = False
End Sub</pre>



<p>Mit <code>e.Cancel = True</code> im <code>FormClosing</code>-Event wird das Schließen des Forms verhindert. Der Benutzer bleibt auf dem Form und kann weiter arbeiten. Mehr zum Schreiben von Dateien findest du im <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>VB.NET Textdatei schreiben Guide</strong></a>.</p>



<h2 class="wp-block-heading">Häufige Fehler</h2>



<h3 class="wp-block-heading">Rückgabewert ignorieren</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - fragt Ja/Nein, ignoriert aber die Antwort
MsgBox("Löschen?", MsgBoxStyle.YesNo)
DeleteRecord()

' GUT - prüfen, welcher Button geklickt wurde
If MsgBox("Löschen?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
    DeleteRecord()
End If</pre>



<h3 class="wp-block-heading">MsgBox mit VBScript-MsgBox verwechseln</h3>



<p>Die VB.NET-<code>MsgBox</code>-Funktion lebt in <code>Microsoft.VisualBasic.Interaction</code> und gibt <code>MsgBoxResult</code> zurück. Die VBScript-<code>MsgBox</code> gibt ganzzahlige Werte zurück (1 für OK, 6 für Ja, usw.). Sie sehen ähnlich aus, laufen aber in komplett unterschiedlichen Umgebungen. In VB.NET immer gegen das <code>MsgBoxResult</code>-Enum vergleichen, nie gegen Magic Numbers.</p>



<h3 class="wp-block-heading">MsgBox in einem Hintergrund-Thread verwenden</h3>



<p>Sowohl <code>MsgBox</code> als auch <code>MessageBox.Show</code> müssen vom UI-Thread aus aufgerufen werden. Wenn du sie aus einem Hintergrund-Thread oder <code>Task</code> aufrufst, kann der Dialog hinter anderen Fenstern erscheinen oder Cross-Thread-Exceptions auslösen. Verwende <code>Me.Invoke()</code>, um den Aufruf auf den UI-Thread zu marshallen.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, von Benutzerdialogen bis zur fertigen Desktop-Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-msgbox-de-1"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen MsgBox und MessageBox.Show?</strong></strong> <p class="schema-faq-answer"><code>MsgBox</code> ist eine VB.NET-Komfortfunktion aus dem <code>Microsoft.VisualBasic</code>-Namespace. <code>MessageBox.Show</code> ist die .NET-Framework-Klasse aus <code>System.Windows.Forms</code>. Beide erzeugen denselben Dialog. <code>MsgBox</code> gibt <code>MsgBoxResult</code> zurück, <code>MessageBox.Show</code> gibt <code>DialogResult</code> zurück.</p> </div> <div class="schema-faq-section" id="faq-msgbox-de-2"><strong class="schema-faq-question"><strong>Wie zeige ich eine Ja/Nein-MsgBox in VB.NET?</strong></strong> <p class="schema-faq-answer">Verwende <code>MsgBox("Deine Frage", MsgBoxStyle.YesNo)</code> und vergleiche das Ergebnis mit <code>MsgBoxResult.Yes</code> oder <code>MsgBoxResult.No</code>. Füge <code>Or MsgBoxStyle.Question</code> hinzu für ein Fragezeichen-Icon.</p> </div> <div class="schema-faq-section" id="faq-msgbox-de-3"><strong class="schema-faq-question"><strong>Wie ändere ich den Standard-Button in MsgBox?</strong></strong> <p class="schema-faq-answer">Füge <code>MsgBoxStyle.DefaultButton2</code> oder <code>DefaultButton3</code> zum Stil-Parameter hinzu. Das verschiebt den initialen Fokus auf den zweiten bzw. dritten Button und verhindert versehentliche Klicks auf destruktive Aktionen.</p> </div> <div class="schema-faq-section" id="faq-msgbox-de-4"><strong class="schema-faq-question"><strong>Ist VB.NET MsgBox dasselbe wie VBScript MsgBox?</strong></strong> <p class="schema-faq-answer">Nein. VB.NET <code>MsgBox</code> gibt ein typisiertes <code>MsgBoxResult</code>-Enum zurück. VBScript <code>MsgBox</code> gibt ganzzahlige Konstanten zurück (1 für OK, 6 für Ja, usw.). Sie sehen ähnlich aus, laufen aber in komplett unterschiedlichen Umgebungen.</p> </div> <div class="schema-faq-section" id="faq-msgbox-de-5"><strong class="schema-faq-question"><strong>Kann ich MsgBox in einem Hintergrund-Thread verwenden?</strong></strong> <p class="schema-faq-answer">Nicht direkt. Sowohl <code>MsgBox</code> als auch <code>MessageBox.Show</code> sollten vom UI-Thread aufgerufen werden. Aus einem Hintergrund-Thread verwende <code>Me.Invoke()</code>, um den Aufruf auf den UI-Thread zu marshallen.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>Die <code>MsgBox</code>-Funktion gibt dir schnelle Meldungsdialoge mit einer Zeile Code. Kombiniere Button- und Icon-Stile mit <code>Or</code>, prüfe immer den Rückgabewert bei Ja/Nein-Abfragen und verwende <code>DefaultButton2</code> vor destruktiven Aktionen. Wenn du .NET-Standardcode bevorzugst, nutze <code>MessageBox.Show</code> mit getrennten Enums für dasselbe Ergebnis. Für dynamisches Event-Handling schau dir den <a href="https://robbelroot.de/blog/vbnet-addhandler/"><strong>VB.NET AddHandler Guide</strong></a> an. Zum Schreiben von Dateien nach einem Speichern-Dialog siehe den <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>VB.NET Textdatei schreiben Guide</strong></a>.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-msgbox/">VB.NET MsgBox – Meldungsdialoge einfach erklärt (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-msgbox/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET FolderBrowserDialog – Ordner auswählen (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-folderbrowserdialog/</link>
					<comments>https://robbelroot.de/blog/vbnet-folderbrowserdialog/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 21:28:17 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20475</guid>

					<description><![CDATA[<p>Der VB.NET FolderBrowserDialog lässt den Benutzer einen Ordner aus dem Dateisystem auswählen, bevor deine Anwendung dessen Inhalte verarbeitet. Er zeigt den Standard-Windows-Ordnerdialog an, gibt den gewählten Pfad zurück und kann den sichtbaren Bereich optional einschränken. Dieser Guide behandelt Einrichtung, Stammordner-Konfiguration, Ordnererstellung, Batch-Verarbeitung und häufige Fehler. Was ist der FolderBrowserDialog? Der &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-folderbrowserdialog/">VB.NET FolderBrowserDialog – Ordner auswählen (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Der <strong>VB.NET FolderBrowserDialog</strong> lässt den Benutzer einen Ordner aus dem Dateisystem auswählen, bevor deine Anwendung dessen Inhalte verarbeitet. Er zeigt den Standard-Windows-Ordnerdialog an, gibt den gewählten Pfad zurück und kann den sichtbaren Bereich optional einschränken. Dieser Guide behandelt Einrichtung, Stammordner-Konfiguration, Ordnererstellung, Batch-Verarbeitung und häufige Fehler.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">.NET-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du baust eine Desktop-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Von Ordnerdialogen bis zur kompletten WinForms-Anwendung kann ich helfen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Was ist der FolderBrowserDialog?</h2>



<p>Der <code>FolderBrowserDialog</code> ist ein WinForms-Control aus <code>System.Windows.Forms</code>. Beim Aufruf von <code>ShowDialog()</code> öffnet sich der Windows-Ordnerdialog. Der Benutzer navigiert durch den Ordnerbaum, wählt einen Ordner aus und klickt OK. Dein Code erhält dann den vollständigen Ordnerpfad über die Eigenschaft <code>SelectedPath</code>.</p>



<p>Verwende ihn, wenn:</p>



<ul class="wp-block-list">
<li>Der Benutzer einen <strong>Ausgabeordner</strong> für Exporte, Backups oder Berichte wählen soll</li>



<li>Deine Anwendung <strong>alle Dateien eines Verzeichnisses</strong> verarbeiten muss</li>



<li>Der Benutzer ein <strong>Installations- oder Arbeitsverzeichnis</strong> auswählen soll</li>



<li>Der Benutzer <strong>einen neuen Ordner anlegen</strong> können soll</li>
</ul>



<p>Falls der Benutzer stattdessen eine einzelne Datei auswählen soll, verwende den <a href="https://robbelroot.de/blog/vbnet-openfiledialog/"><strong>OpenFileDialog</strong></a>. Zum Speichern einer Datei an einem bestimmten Ort verwende den <a href="https://robbelroot.de/blog/vbnet-savefiledialog/"><strong>SaveFileDialog</strong></a>.</p>



<h2 class="wp-block-heading">Einfaches Beispiel</h2>



<p>Der einfachste FolderBrowserDialog, der den gewählten Pfad anzeigt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New FolderBrowserDialog()
    dlg.Description = "Ordner auswählen"

    If dlg.ShowDialog() = DialogResult.OK Then
        MessageBox.Show($"Gewählt: {dlg.SelectedPath}")
    End If
End Using</pre>



<p>Der <code>Using</code>-Block gibt den Dialog nach der Verwendung frei. <code>ShowDialog()</code> gibt <code>DialogResult.OK</code> zurück, wenn der Benutzer bestätigt, oder <code>DialogResult.Cancel</code>, wenn er den Dialog schließt. Prüfe immer das Ergebnis, bevor du den Pfad verwendest.</p>



<h2 class="wp-block-heading">Stammordner einschränken</h2>



<p>Die <code>RootFolder</code>-Eigenschaft legt fest, welcher Knotenpunkt als oberste Ebene im Dialog angezeigt wird. Sie akzeptiert Werte aus <code>Environment.SpecialFolder</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New FolderBrowserDialog()
    ' Nur Ordner innerhalb des Desktops anzeigen
    dlg.RootFolder = Environment.SpecialFolder.Desktop
    dlg.Description = "Projektordner auswählen"

    If dlg.ShowDialog() = DialogResult.OK Then
        Dim folder As String = dlg.SelectedPath
    End If
End Using</pre>



<p>Gängige Werte für <code>RootFolder</code>:</p>



<ul class="wp-block-list">
<li><code>Environment.SpecialFolder.Desktop</code> (Standard) zeigt den kompletten Baum ab dem Desktop</li>



<li><code>Environment.SpecialFolder.MyComputer</code> zeigt alle Laufwerke</li>



<li><code>Environment.SpecialFolder.MyDocuments</code> beschränkt das Browsen auf den Dokumente-Ordner</li>
</ul>



<h2 class="wp-block-heading">Ordner vorauswählen</h2>



<p>Verwende <code>SelectedPath</code>, um beim Öffnen des Dialogs einen Ordner vorzuwählen. Das ist nützlich, wenn der Benutzer zuvor bereits einen Ordner gewählt hat und du dir den merken willst:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New FolderBrowserDialog()
    dlg.Description = "Exportordner auswählen"
    dlg.SelectedPath = "C:\Users\Public\Documents"

    If dlg.ShowDialog() = DialogResult.OK Then
        Dim exportFolder As String = dlg.SelectedPath
    End If
End Using</pre>



<p>Der Dialog öffnet sich mit diesem Ordner bereits markiert. Falls der Pfad nicht existiert, springt der Dialog zum Stammordner zurück.</p>



<h2 class="wp-block-heading">Neuer-Ordner-Button ausblenden</h2>



<p>Standardmäßig enthält der Dialog einen &#8222;Neuen Ordner erstellen&#8220;-Button. Wenn der Benutzer nur einen existierenden Ordner auswählen soll, deaktiviere ihn:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New FolderBrowserDialog()
    dlg.Description = "Vorhandenen Ordner auswählen"
    dlg.ShowNewFolderButton = False

    If dlg.ShowDialog() = DialogResult.OK Then
        Dim folder As String = dlg.SelectedPath
    End If
End Using</pre>



<p>Setze <code>ShowNewFolderButton = False</code> für reine Leseoperationen wie den Import von Dateien. Lass ihn auf <code>True</code> (Standard), wenn der Benutzer eventuell einen Zielordner für Exporte anlegen muss.</p>



<h2 class="wp-block-heading">Komplettes Beispiel: Dateien im Batch verarbeiten</h2>



<p>Ein realistisches Beispiel, das den Benutzer einen Ordner auswählen lässt und dann alle Textdateien darin verarbeitet:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports System.IO
Imports System.Text

Private Sub BtnImportieren_Click(sender As Object, e As EventArgs) Handles BtnImportieren.Click
    Using dlg As New FolderBrowserDialog()
        dlg.Description = "Ordner mit Textdateien auswählen"
        dlg.ShowNewFolderButton = False

        If dlg.ShowDialog() = DialogResult.OK Then
            Dim files() As String = Directory.GetFiles(
                dlg.SelectedPath, "*.txt")

            For Each filePath In files
                Dim content As String = File.ReadAllText(
                    filePath, Encoding.UTF8)
                ' Jede Datei verarbeiten...
            Next

            MessageBox.Show($"{files.Length} Dateien verarbeitet.")
        End If
    End Using
End Sub</pre>



<p><code>Directory.GetFiles()</code> gibt alle passenden Dateien im gewählten Ordner zurück. Verwende den zweiten Parameter für Muster, z.B. <code>"*.csv"</code> oder <code>"*.xml"</code>. Mehr zum Lesen von Textdateien findest du im <a href="https://robbelroot.de/blog/vbnet-textdatei-einlesen/"><strong>VB.NET Textdatei einlesen Guide</strong></a>.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du eine fertige WinForms-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von Dateidialogen bis zur kompletten datengetriebenen Desktop-App: Ich entwerfe Software, die hält. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Unterordner einbeziehen</h2>



<p>Um Dateien rekursiv zu verarbeiten, füge <code>SearchOption.AllDirectories</code> hinzu:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">If dlg.ShowDialog() = DialogResult.OK Then
    Dim files() As String = Directory.GetFiles(
        dlg.SelectedPath, "*.txt", SearchOption.AllDirectories)

    For Each filePath In files
        Dim relativePath As String = filePath.Replace(
            dlg.SelectedPath & "\", "")
        ' Datei mit relativem Pfad verarbeiten...
    Next
End If</pre>



<p>Das durchsucht den gewählten Ordner und alle seine Unterordner. Sei vorsichtig bei großen Verzeichnisbäumen, da dies bei Tausenden von Dateien eine Weile dauern kann.</p>



<h2 class="wp-block-heading">Environment.SpecialFolder verwenden</h2>



<p>Du kannst den Dialog mit <code>Environment.GetFolderPath()</code> kombinieren, um gängige Systemordner vorzuwählen. Du kannst auch den <a href="https://robbelroot.de/blog/vbnet-application-path/"><strong>Anwendungspfad</strong></a> als Startpunkt verwenden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' In Dokumente starten
Using dlg As New FolderBrowserDialog()
    dlg.SelectedPath = Environment.GetFolderPath(
        Environment.SpecialFolder.MyDocuments)

    If dlg.ShowDialog() = DialogResult.OK Then
        ' dlg.SelectedPath verwenden...
    End If
End Using

' Im Anwendungsverzeichnis starten
Using dlg As New FolderBrowserDialog()
    dlg.SelectedPath = Application.StartupPath

    If dlg.ShowDialog() = DialogResult.OK Then
        ' dlg.SelectedPath verwenden...
    End If
End Using</pre>



<h2 class="wp-block-heading">Alle wichtigen Eigenschaften im Überblick</h2>



<figure class="wp-block-table"><table><thead><tr><th>Eigenschaft</th><th>Standard</th><th>Zweck</th></tr></thead><tbody><tr><td><code>Description</code></td><td>(leer)</td><td>Text über dem Ordnerbaum</td></tr><tr><td><code>SelectedPath</code></td><td>(leer)</td><td>Vorgewählter / gewählter Ordner nach dem Dialog</td></tr><tr><td><code>RootFolder</code></td><td>Desktop</td><td>Oberstes Element im Ordnerbaum</td></tr><tr><td><code>ShowNewFolderButton</code></td><td>True</td><td>&#8222;Neuen Ordner erstellen&#8220;-Button ein- oder ausblenden</td></tr></tbody></table></figure>



<p>Der FolderBrowserDialog hat weniger Eigenschaften als der <a href="https://robbelroot.de/blog/vbnet-openfiledialog/"><strong>OpenFileDialog</strong></a>, weil er nur Ordner und keine Dateien behandelt. Es gibt keine <code>Filter</code>&#8211; oder <code>Multiselect</code>-Eigenschaft.</p>



<h2 class="wp-block-heading">Häufige Fehler</h2>



<h3 class="wp-block-heading">Pfad verwenden ohne DialogResult zu prüfen</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - SelectedPath ist leer, wenn der Benutzer abbricht
dlg.ShowDialog()
Dim files = Directory.GetFiles(dlg.SelectedPath)

' GUT - Ergebnis zuerst prüfen
If dlg.ShowDialog() = DialogResult.OK Then
    Dim files = Directory.GetFiles(dlg.SelectedPath)
End If</pre>



<h3 class="wp-block-heading">RootFolder und SelectedPath verwechseln</h3>



<p><code>RootFolder</code> schränkt ein, welche Ordner der Benutzer sehen kann. <code>SelectedPath</code> wählt einen Ordner innerhalb des sichtbaren Baums vor. Wenn du <code>RootFolder = MyDocuments</code> setzt, kann der Benutzer nicht aus den Dokumenten herausnavigieren. Wenn du nur einen Startpunkt vorschlagen, aber volle Navigation erlauben willst, verwende stattdessen <code>SelectedPath</code>.</p>



<h3 class="wp-block-heading">Using-Block vergessen</h3>



<p>Wie alle WinForms-Dialoge hält der FolderBrowserDialog unverwaltete Ressourcen. Ohne <code>Using</code> bleiben diese Ressourcen im Speicher, bis der Garbage Collector läuft. Wickle ihn immer in einen <code>Using</code>-Block ein.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, von Dateioperationen bis zur fertigen Desktop-Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-folderbrowser-de-1"><strong class="schema-faq-question"><strong>Wie öffne ich einen FolderBrowserDialog in VB.NET?</strong></strong> <p class="schema-faq-answer">Erstelle einen <code>New FolderBrowserDialog()</code> in einem <code>Using</code>-Block, setze optional <code>Description</code> und rufe <code>ShowDialog()</code> auf. Prüfe, ob das Ergebnis <code>DialogResult.OK</code> ist, bevor du <code>dlg.SelectedPath</code> verwendest.</p> </div> <div class="schema-faq-section" id="faq-folderbrowser-de-2"><strong class="schema-faq-question"><strong>Wie setze ich den Standardordner im FolderBrowserDialog?</strong></strong> <p class="schema-faq-answer">Setze <code>dlg.SelectedPath</code> auf den gewünschten Ordnerpfad, bevor du <code>ShowDialog()</code> aufrufst. Der Dialog öffnet sich mit diesem Ordner markiert. Verwechsle das nicht mit <code>RootFolder</code>, das den sichtbaren Baum einschränkt.</p> </div> <div class="schema-faq-section" id="faq-folderbrowser-de-3"><strong class="schema-faq-question"><strong>Kann ich den Neuer-Ordner-Button ausblenden?</strong></strong> <p class="schema-faq-answer">Ja. Setze <code>dlg.ShowNewFolderButton = False</code> vor dem Aufruf von <code>ShowDialog()</code>. Das ist nützlich für reine Leseoperationen, bei denen der Benutzer nur einen bestehenden Ordner auswählen soll.</p> </div> <div class="schema-faq-section" id="faq-folderbrowser-de-4"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen RootFolder und SelectedPath?</strong></strong> <p class="schema-faq-answer"><code>RootFolder</code> begrenzt das oberste Element, das der Benutzer durchsuchen kann, und schränkt die Navigation ein. <code>SelectedPath</code> wählt einen Ordner innerhalb des sichtbaren Baums vor, ohne die Navigation einzuschränken. Verwende <code>SelectedPath</code>, wenn du einen Startpunkt willst, aber vollen Zugriff erlauben möchtest.</p> </div> <div class="schema-faq-section" id="faq-folderbrowser-de-5"><strong class="schema-faq-question"><strong>Kann der Benutzer mehrere Ordner auswählen?</strong></strong> <p class="schema-faq-answer">Nein. Der eingebaute <code>FolderBrowserDialog</code> unterstützt nur die Auswahl eines einzelnen Ordners. Für die Auswahl mehrerer Ordner müsstest du den Dialog mehrfach aufrufen oder eine eigene Lösung implementieren.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>Der <code>FolderBrowserDialog</code> gibt deiner VB.NET-Anwendung einen nativen Ordnerdialog mit minimalem Code. Setze <code>SelectedPath</code> um einen Startordner vorzuschlagen, verwende <code>RootFolder</code> um die Navigation einzuschränken, und blende den Neuer-Ordner-Button mit <code>ShowNewFolderButton = False</code> aus, wenn der Benutzer nur existierende Ordner wählen soll. Nach dem Dialog kombiniere <code>SelectedPath</code> mit <code>Directory.GetFiles()</code> um den Ordnerinhalt zu verarbeiten. Für die Auswahl einzelner Dateien verwende den <a href="https://robbelroot.de/blog/vbnet-openfiledialog/"><strong>OpenFileDialog</strong></a>. Zum Speichern von Dateien siehe den <a href="https://robbelroot.de/blog/vbnet-savefiledialog/"><strong>SaveFileDialog</strong></a>.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-folderbrowserdialog/">VB.NET FolderBrowserDialog – Ordner auswählen (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-folderbrowserdialog/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET OpenFileDialog – Datei öffnen mit Dialog (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-openfiledialog/</link>
					<comments>https://robbelroot.de/blog/vbnet-openfiledialog/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 21:16:10 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20469</guid>

					<description><![CDATA[<p>Der VB.NET OpenFileDialog lässt den Benutzer eine oder mehrere Dateien zum Öffnen auswählen, bevor deine Anwendung sie einliest. Er übernimmt Pfadauswahl, Dateitypfilter und Datei-Existenz-Prüfung in einem einzigen Control. Dieser Guide behandelt Einrichtung, Filter, Mehrfachauswahl, gängige Muster und die Integration mit dem eigentlichen Lesevorgang. Was ist der OpenFileDialog? Der OpenFileDialog ist &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-openfiledialog/">VB.NET OpenFileDialog – Datei öffnen mit Dialog (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Der <strong>VB.NET OpenFileDialog</strong> lässt den Benutzer eine oder mehrere Dateien zum Öffnen auswählen, bevor deine Anwendung sie einliest. Er übernimmt Pfadauswahl, Dateitypfilter und Datei-Existenz-Prüfung in einem einzigen Control. Dieser Guide behandelt Einrichtung, Filter, Mehrfachauswahl, gängige Muster und die Integration mit dem eigentlichen Lesevorgang.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">.NET-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du baust eine Desktop-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Von Dateidialogen bis zur kompletten WinForms-Anwendung kann ich helfen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Was ist der OpenFileDialog?</h2>



<p>Der <code>OpenFileDialog</code> ist ein WinForms-Control aus <code>System.Windows.Forms</code>. Beim Aufruf von <code>ShowDialog()</code> öffnet sich der Standard-Windows-Dialog &#8222;Öffnen&#8220;. Der Benutzer navigiert zu einem Ordner, wählt eine Datei aus und klickt Öffnen. Dein Code erhält dann den vollständigen Dateipfad über die Eigenschaft <code>FileName</code>.</p>



<p>Verwende ihn, wenn:</p>



<ul class="wp-block-list">
<li>Der Benutzer <strong>wählen soll, welche Datei geöffnet wird</strong> (Importe, Konfigdateien, Bilder)</li>



<li>Du einen <strong>Dateitypfilter</strong> brauchst (z.B. nur .txt, .csv oder .png)</li>



<li>Du eine <strong>eingebaute Prüfung</strong> willst, ob die gewählte Datei tatsächlich existiert</li>



<li>Der Benutzer <strong>mehrere Dateien gleichzeitig auswählen</strong> können soll</li>
</ul>



<p>Falls der Benutzer stattdessen ein Speicherziel wählen soll, verwende den <a href="https://robbelroot.de/blog/vbnet-savefiledialog/"><strong>SaveFileDialog</strong></a>.</p>



<h2 class="wp-block-heading">Einfaches Beispiel</h2>



<p>Der einfachste OpenFileDialog, der eine Textdatei einliest:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New OpenFileDialog()
    dlg.Filter = "Textdateien (*.txt)|*.txt"
    dlg.Title = "Textdatei öffnen"

    If dlg.ShowDialog() = DialogResult.OK Then
        Dim content As String = File.ReadAllText(dlg.FileName)
        TextBox1.Text = content
    End If
End Using</pre>



<p>Der <code>Using</code>-Block gibt den Dialog nach der Verwendung frei. <code>ShowDialog()</code> gibt <code>DialogResult.OK</code> zurück, wenn der Benutzer auf Öffnen klickt, oder <code>DialogResult.Cancel</code>, wenn er den Dialog schließt. Prüfe immer das Ergebnis, bevor du die Datei liest.</p>



<h2 class="wp-block-heading">Dateitypfilter einrichten</h2>



<p>Die <code>Filter</code>-Eigenschaft steuert, welche Dateitypen im Dropdown erscheinen. Die Syntax ist identisch zum <a href="https://robbelroot.de/blog/vbnet-savefiledialog/"><strong>SaveFileDialog</strong></a>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Einzelner Filter
dlg.Filter = "Textdateien (*.txt)|*.txt"

' Mehrere Filter
dlg.Filter = "Textdateien (*.txt)|*.txt|CSV-Dateien (*.csv)|*.csv|Alle Dateien (*.*)|*.*"

' Zweiten Filter vorauswählen (1-basierter Index)
dlg.FilterIndex = 2

' Mehrere Endungen in einem Filter
dlg.Filter = "Bilder (*.png;*.jpg;*.gif)|*.png;*.jpg;*.gif"</pre>



<p>Um mehrere Endungen in einem Filtereintrag zu kombinieren, trenne sie mit Semikolons im Muster-Teil: <code>*.png;*.jpg;*.gif</code>. Der Benutzer sieht einen einzelnen &#8222;Bilder&#8220;-Eintrag, der alle drei Typen akzeptiert.</p>



<h2 class="wp-block-heading">Standardordner setzen</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New OpenFileDialog()
    ' Im Dokumente-Ordner des Benutzers starten
    dlg.InitialDirectory = Environment.GetFolderPath(
        Environment.SpecialFolder.MyDocuments)

    dlg.Filter = "CSV-Dateien (*.csv)|*.csv"

    If dlg.ShowDialog() = DialogResult.OK Then
        Dim content As String = File.ReadAllText(dlg.FileName)
    End If
End Using</pre>



<p>Gängige Optionen für <code>InitialDirectory</code>:</p>



<ul class="wp-block-list">
<li><code>Environment.SpecialFolder.MyDocuments</code> für Benutzerdokumente</li>



<li><code>Environment.SpecialFolder.Desktop</code> für den Desktop</li>



<li>Den <a href="https://robbelroot.de/blog/vbnet-application-path/"><strong>Application Path</strong></a> für Dateien neben der Anwendung</li>
</ul>



<p>Wenn du <code>InitialDirectory</code> nicht setzt, merkt sich der Dialog den zuletzt besuchten Ordner während der aktuellen Sitzung.</p>



<h2 class="wp-block-heading">Mehrere Dateien auswählen</h2>



<p>Setze <code>Multiselect = True</code>, damit der Benutzer mehrere Dateien auswählen kann. Die gewählten Pfade sind über <code>FileNames</code> (Plural) verfügbar:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New OpenFileDialog()
    dlg.Filter = "Bilder (*.png;*.jpg)|*.png;*.jpg"
    dlg.Multiselect = True
    dlg.Title = "Bilder zum Importieren auswählen"

    If dlg.ShowDialog() = DialogResult.OK Then
        For Each filePath In dlg.FileNames
            Dim img As Image = Image.FromFile(filePath)
            ' Jedes Bild verarbeiten...
        Next

        MessageBox.Show($"{dlg.FileNames.Length} Dateien ausgewählt.")
    End If
End Using</pre>



<p>Der Benutzer hält Strg gedrückt, um einzelne Dateien auszuwählen, oder Shift für einen Bereich. <code>FileName</code> (Singular) gibt weiterhin die erste gewählte Datei zurück; <code>FileNames</code> liefert alle als <code>String()</code>-Array.</p>



<h2 class="wp-block-heading">Komplettes Beispiel: Textdatei einlesen</h2>



<p>Ein realistisches Beispiel, das eine Textdatei mit Encoding-Unterstützung einliest, unter Verwendung von <a href="https://robbelroot.de/blog/vbnet-textdatei-einlesen/"><strong>ReadAllText</strong></a>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports System.IO
Imports System.Text

Private Sub BtnOeffnen_Click(sender As Object, e As EventArgs) Handles BtnOeffnen.Click
    Using dlg As New OpenFileDialog()
        dlg.Title = "Bericht öffnen"
        dlg.Filter = "Textdateien (*.txt)|*.txt|CSV-Dateien (*.csv)|*.csv|Alle Dateien (*.*)|*.*"
        dlg.InitialDirectory = Environment.GetFolderPath(
            Environment.SpecialFolder.MyDocuments)

        If dlg.ShowDialog() = DialogResult.OK Then
            Dim content As String = File.ReadAllText(dlg.FileName, Encoding.UTF8)
            TextBox1.Text = content
            Me.Text = $"Editor - {Path.GetFileName(dlg.FileName)}"
        End If
    End Using
End Sub</pre>



<p>Gib beim Lesen von Textdateien immer <code>Encoding.UTF8</code> an, um Sonderzeichen korrekt zu verarbeiten. <code>Path.GetFileName()</code> extrahiert nur den Dateinamen aus dem vollen Pfad, was z.B. für den Fenstertitel nützlich ist.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du eine fertige WinForms-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von Dateidialogen bis zur kompletten datengetriebenen Desktop-App: Ich entwerfe Software, die hält. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Binärdateien lesen (Bilder, PDFs)</h2>



<p>Der OpenFileDialog funktioniert für binäre Inhalte genauso. Nur die Lesemethode ändert sich:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Bild in eine PictureBox laden
Using dlg As New OpenFileDialog()
    dlg.Filter = "Bilder (*.png;*.jpg;*.bmp)|*.png;*.jpg;*.bmp"

    If dlg.ShowDialog() = DialogResult.OK Then
        PictureBox1.Image = Image.FromFile(dlg.FileName)
    End If
End Using

' Datei als Byte-Array einlesen
Using dlg As New OpenFileDialog()
    dlg.Filter = "Alle Dateien (*.*)|*.*"

    If dlg.ShowDialog() = DialogResult.OK Then
        Dim bytes() As Byte = File.ReadAllBytes(dlg.FileName)
        ' Bytes verarbeiten...
    End If
End Using</pre>



<h2 class="wp-block-heading">Große Dateien mit StreamReader lesen</h2>



<p>Für große Dateien oder zeilenweise Verarbeitung verwende einen <code>StreamReader</code> mit dem Pfad aus dem Dialog:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New OpenFileDialog()
    dlg.Filter = "CSV-Dateien (*.csv)|*.csv"

    If dlg.ShowDialog() = DialogResult.OK Then
        Using reader As New StreamReader(dlg.FileName, Encoding.UTF8)
            Dim lineNumber As Integer = 0
            While Not reader.EndOfStream
                Dim line As String = reader.ReadLine()
                lineNumber += 1
                ' Jede Zeile verarbeiten...
            End While
        End Using
    End If
End Using</pre>



<p>Der <code>StreamReader</code>-Ansatz ist speichereffizienter für große Dateien, weil er Zeile für Zeile liest, statt die gesamte Datei in den Speicher zu laden. Mehr zum Lesen von Textdateien findest du im <a href="https://robbelroot.de/blog/vbnet-textdatei-einlesen/"><strong>VB.NET Textdatei einlesen Guide</strong></a>.</p>



<h2 class="wp-block-heading">Alle wichtigen Eigenschaften im Überblick</h2>



<figure class="wp-block-table"><table><thead><tr><th>Eigenschaft</th><th>Standard</th><th>Zweck</th></tr></thead><tbody><tr><td><code>Filter</code></td><td>(leer)</td><td>Einträge im Dateityp-Dropdown</td></tr><tr><td><code>FilterIndex</code></td><td>1</td><td>Vorausgewählter Filter (1-basiert)</td></tr><tr><td><code>FileName</code></td><td>(leer)</td><td>Gewählter Dateipfad nach dem Dialog</td></tr><tr><td><code>FileNames</code></td><td>(leer)</td><td>Alle gewählten Pfade bei Multiselect</td></tr><tr><td><code>InitialDirectory</code></td><td>(leer)</td><td>Startordner</td></tr><tr><td><code>Multiselect</code></td><td>False</td><td>Mehrfachauswahl erlauben</td></tr><tr><td><code>CheckFileExists</code></td><td>True</td><td>Pfade ablehnen, die nicht existieren</td></tr><tr><td><code>CheckPathExists</code></td><td>True</td><td>Ungültige Ordnerpfade ablehnen</td></tr><tr><td><code>Title</code></td><td>&#8222;Öffnen&#8220;</td><td>Fenstertitel des Dialogs</td></tr><tr><td><code>ReadOnlyChecked</code></td><td>False</td><td>&#8222;Schreibgeschützt öffnen&#8220;-Checkbox vorauswählen</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Häufige Fehler</h2>



<h3 class="wp-block-heading">Lesen ohne DialogResult zu prüfen</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - FileName ist leer, wenn der Benutzer abbricht
dlg.ShowDialog()
Dim content = File.ReadAllText(dlg.FileName)

' GUT - Ergebnis zuerst prüfen
If dlg.ShowDialog() = DialogResult.OK Then
    Dim content = File.ReadAllText(dlg.FileName)
End If</pre>



<h3 class="wp-block-heading">FileName statt FileNames bei Multiselect</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - bekommt nur die erste Datei bei Multiselect
dlg.Multiselect = True
If dlg.ShowDialog() = DialogResult.OK Then
    Dim content = File.ReadAllText(dlg.FileName)  ' nur erste Datei!
End If

' GUT - alle gewählten Dateien durchlaufen
If dlg.ShowDialog() = DialogResult.OK Then
    For Each path In dlg.FileNames
        Dim content = File.ReadAllText(path)
    Next
End If</pre>



<h3 class="wp-block-heading">Using-Block vergessen</h3>



<p>Der OpenFileDialog hält unverwaltete Ressourcen (ein Windows-COM-Objekt). Ohne <code>Using</code> bleiben diese Ressourcen im Speicher, bis der Garbage Collector läuft. Wickle ihn immer in einen <code>Using</code>-Block ein.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, von Dateioperationen bis zur fertigen Desktop-Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-openfile-de-1"><strong class="schema-faq-question"><strong>Wie öffne ich einen OpenFileDialog in VB.NET?</strong></strong> <p class="schema-faq-answer">Erstelle einen <code>New OpenFileDialog()</code> in einem <code>Using</code>-Block, setze die <code>Filter</code>-Eigenschaft und rufe <code>ShowDialog()</code> auf. Prüfe, ob das Ergebnis <code>DialogResult.OK</code> ist, bevor du aus <code>dlg.FileName</code> liest.</p> </div> <div class="schema-faq-section" id="faq-openfile-de-2"><strong class="schema-faq-question"><strong>Wie wähle ich mehrere Dateien mit dem OpenFileDialog aus?</strong></strong> <p class="schema-faq-answer">Setze <code>dlg.Multiselect = True</code> vor dem Aufruf von <code>ShowDialog()</code>. Der Benutzer kann dann mit Strg oder Shift mehrere Dateien auswählen. Alle Pfade stehen in <code>dlg.FileNames</code> (Plural).</p> </div> <div class="schema-faq-section" id="faq-openfile-de-3"><strong class="schema-faq-question"><strong>Wie filtere ich Dateitypen im OpenFileDialog?</strong></strong> <p class="schema-faq-answer">Setze die <code>Filter</code>-Eigenschaft mit dem Muster <code>Beschreibung|*.endung</code>. Für mehrere Typen trenne sie mit Pipes: <code>"Text (*.txt)|*.txt|CSV (*.csv)|*.csv"</code>. Kombiniere Endungen mit Semikolons: <code>"Bilder (*.png;*.jpg)|*.png;*.jpg"</code>.</p> </div> <div class="schema-faq-section" id="faq-openfile-de-4"><strong class="schema-faq-question"><strong>Liest der OpenFileDialog die Datei selbst?</strong></strong> <p class="schema-faq-answer">Nein. Der Dialog lässt den Benutzer nur einen Dateipfad wählen. Du bist selbst dafür verantwortlich, die Datei zu lesen, z.B. mit <code>File.ReadAllText()</code>, <code>File.ReadAllBytes()</code> oder einem StreamReader mit dem Pfad aus <code>dlg.FileName</code>.</p> </div> <div class="schema-faq-section" id="faq-openfile-de-5"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen OpenFileDialog und SaveFileDialog?</strong></strong> <p class="schema-faq-answer">Der OpenFileDialog lässt den Benutzer eine bestehende Datei zum Lesen auswählen, mit eingebauter Existenz-Prüfung. Der SaveFileDialog lässt den Benutzer ein Ziel für eine neue Datei wählen, mit Überschreib-Bestätigung. Beide geben den gewählten Pfad über <code>FileName</code> zurück.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>Der <code>OpenFileDialog</code> gibt deiner VB.NET-Anwendung ein natives Datei-Öffnen-Erlebnis mit minimalem Code. Setze einen <code>Filter</code> für Dateitypen, aktiviere <code>Multiselect</code> für Batch-Operationen und prüfe immer <code>DialogResult.OK</code> bevor du liest. Für den eigentlichen Lesevorgang verwende <code>File.ReadAllText()</code> für Text oder <code>File.ReadAllBytes()</code> für Binärdaten. Musst du stattdessen Dateien speichern? Der <a href="https://robbelroot.de/blog/vbnet-savefiledialog/"><strong>SaveFileDialog</strong></a> funktioniert nach dem gleichen Muster. Mehr zum Lesen von Textdateien findest du im <a href="https://robbelroot.de/blog/vbnet-textdatei-einlesen/"><strong>VB.NET Textdatei einlesen Guide</strong></a>.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-openfiledialog/">VB.NET OpenFileDialog – Datei öffnen mit Dialog (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-openfiledialog/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET SaveFileDialog – Datei speichern mit Dialog (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-savefiledialog/</link>
					<comments>https://robbelroot.de/blog/vbnet-savefiledialog/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 20:36:00 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20463</guid>

					<description><![CDATA[<p>Der VB.NET SaveFileDialog lässt den Benutzer einen Dateinamen und Speicherort wählen, bevor deine Anwendung Daten auf die Festplatte schreibt. Er übernimmt Pfadauswahl, Dateitypfilter und Überschreib-Bestätigung in einem einzigen Control. Dieser Guide behandelt Einrichtung, Filter, Standardpfade, gängige Muster und die Integration mit dem eigentlichen Schreibvorgang. Was ist der SaveFileDialog? Der SaveFileDialog &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-savefiledialog/">VB.NET SaveFileDialog – Datei speichern mit Dialog (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Der <strong>VB.NET SaveFileDialog</strong> lässt den Benutzer einen Dateinamen und Speicherort wählen, bevor deine Anwendung Daten auf die Festplatte schreibt. Er übernimmt Pfadauswahl, Dateitypfilter und Überschreib-Bestätigung in einem einzigen Control. Dieser Guide behandelt Einrichtung, Filter, Standardpfade, gängige Muster und die Integration mit dem eigentlichen Schreibvorgang.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">.NET-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du baust eine Desktop-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Von Dateidialogen bis zur kompletten WinForms-Anwendung kann ich helfen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Was ist der SaveFileDialog?</h2>



<p>Der <code>SaveFileDialog</code> ist ein WinForms-Control aus <code>System.Windows.Forms</code>. Beim Aufruf von <code>ShowDialog()</code> öffnet sich der Standard-Windows-Dialog &#8222;Speichern unter&#8220;. Der Benutzer wählt einen Ordner, gibt einen Dateinamen ein und klickt Speichern. Dein Code erhält dann den vollständigen Dateipfad über die Eigenschaft <code>FileName</code>.</p>



<p>Verwende ihn, wenn:</p>



<ul class="wp-block-list">
<li>Der Benutzer <strong>wählen soll, wo eine Datei gespeichert wird</strong> (Exporte, Berichte, Downloads)</li>



<li>Du einen <strong>Dateitypfilter</strong> brauchst (z.B. nur .txt, .csv oder .pdf)</li>



<li>Du eine <strong>eingebaute Überschreib-Bestätigung</strong> willst, ohne sie selbst zu programmieren</li>
</ul>



<h2 class="wp-block-heading">Einfaches Beispiel</h2>



<p>Der einfachste SaveFileDialog mit einem einzelnen Dateityp:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New SaveFileDialog()
    dlg.Filter = "Textdateien (*.txt)|*.txt"
    dlg.Title = "Textdatei speichern"

    If dlg.ShowDialog() = DialogResult.OK Then
        File.WriteAllText(dlg.FileName, "Hallo Welt")
    End If
End Using</pre>



<p>Der <code>Using</code>-Block gibt den Dialog nach der Verwendung frei. <code>ShowDialog()</code> gibt <code>DialogResult.OK</code> zurück, wenn der Benutzer auf Speichern klickt, oder <code>DialogResult.Cancel</code>, wenn er den Dialog schließt. Prüfe immer das Ergebnis, bevor du schreibst.</p>



<h2 class="wp-block-heading">Dateitypfilter einrichten</h2>



<p>Die <code>Filter</code>-Eigenschaft steuert, welche Dateitypen im Dropdown erscheinen. Die Syntax ist <code>Beschreibung|Muster</code>, getrennt durch Pipes für mehrere Typen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Einzelner Filter
dlg.Filter = "Textdateien (*.txt)|*.txt"

' Mehrere Filter
dlg.Filter = "Textdateien (*.txt)|*.txt|CSV-Dateien (*.csv)|*.csv|Alle Dateien (*.*)|*.*"

' Zweiten Filter vorauswählen (1-basierter Index)
dlg.FilterIndex = 2</pre>



<p>Jeder Filtereintrag besteht aus zwei Teilen: dem Anzeigetext (z.B. &#8222;Textdateien (*.txt)&#8220;) und dem eigentlichen Muster (z.B. &#8222;*.txt&#8220;). <code>FilterIndex</code> ist 1-basiert, also wählt <code>2</code> den zweiten Eintrag aus.</p>



<h3 class="wp-block-heading">Dateiendung automatisch anhängen</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Endung anhängen, wenn der Benutzer keine eingibt (Standard: True)
dlg.AddExtension = True

' Standard-Endung setzen (ohne den Punkt)
dlg.DefaultExt = "txt"</pre>



<p>Mit <code>AddExtension = True</code> (Standard) hängt der Dialog &#8222;.txt&#8220; an, wenn der Benutzer nur &#8222;bericht&#8220; ohne Endung eingibt. Die Endung kommt aus dem ausgewählten Filter oder dem <code>DefaultExt</code>-Wert.</p>



<h2 class="wp-block-heading">Standardordner und Dateiname setzen</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New SaveFileDialog()
    ' Im Dokumente-Ordner des Benutzers starten
    dlg.InitialDirectory = Environment.GetFolderPath(
        Environment.SpecialFolder.MyDocuments)

    ' Dateiname vorausfüllen
    dlg.FileName = "bericht-2026.csv"

    dlg.Filter = "CSV-Dateien (*.csv)|*.csv"

    If dlg.ShowDialog() = DialogResult.OK Then
        File.WriteAllText(dlg.FileName, csvContent)
    End If
End Using</pre>



<p><code>InitialDirectory</code> legt fest, wo der Dialog öffnet. Gängige Optionen:</p>



<ul class="wp-block-list">
<li><code>Environment.SpecialFolder.MyDocuments</code> für Benutzerdokumente</li>



<li><code>Environment.SpecialFolder.Desktop</code> für den Desktop</li>



<li>Den <a href="https://robbelroot.de/blog/vbnet-application-path/"><strong>Application Path</strong></a> zum Speichern neben der Anwendung</li>
</ul>



<p>Wenn du <code>InitialDirectory</code> nicht setzt, merkt sich der Dialog den zuletzt besuchten Ordner während der aktuellen Sitzung.</p>



<h2 class="wp-block-heading">Überschreib-Bestätigung</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Warnung anzeigen, wenn die Datei bereits existiert (Standard: True)
dlg.OverwritePrompt = True</pre>



<p>Diese Option ist standardmäßig aktiviert. Wenn der Benutzer eine bestehende Datei auswählt, zeigt Windows einen Bestätigungsdialog. Das musst du nicht selbst programmieren.</p>



<h2 class="wp-block-heading">Komplettes Beispiel: Textdatei speichern</h2>



<p>Ein realistisches Beispiel, das eine mehrzeilige Textdatei mit Encoding-Unterstützung speichert, unter Verwendung von <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>WriteAllText</strong></a>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports System.IO
Imports System.Text

Private Sub BtnSpeichern_Click(sender As Object, e As EventArgs) Handles BtnSpeichern.Click
    Using dlg As New SaveFileDialog()
        dlg.Title = "Bericht speichern"
        dlg.Filter = "Textdateien (*.txt)|*.txt|CSV-Dateien (*.csv)|*.csv"
        dlg.InitialDirectory = Environment.GetFolderPath(
            Environment.SpecialFolder.MyDocuments)
        dlg.FileName = $"bericht-{DateTime.Now:yyyy-MM-dd}"

        If dlg.ShowDialog() = DialogResult.OK Then
            Dim content As String = BuildReport()
            File.WriteAllText(dlg.FileName, content, Encoding.UTF8)
            MessageBox.Show($"Gespeichert unter {dlg.FileName}",
                "Erfolg", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End If
    End Using
End Sub</pre>



<p>Gib beim Schreiben von Textdateien immer <code>Encoding.UTF8</code> an. Ohne diese Angabe verwendet .NET das System-Standard-Encoding, was auf anderen Rechnern zu Problemen mit Sonderzeichen führen kann.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du eine fertige WinForms-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von Dateidialogen bis zur kompletten datengetriebenen Desktop-App: Ich entwerfe Software, die hält. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Binärdateien speichern (Bilder, PDFs)</h2>



<p>Der SaveFileDialog funktioniert für binäre Inhalte genauso. Der einzige Unterschied ist die Schreibmethode:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Bild speichern
Using dlg As New SaveFileDialog()
    dlg.Filter = "PNG-Bilder (*.png)|*.png|JPEG-Bilder (*.jpg)|*.jpg"
    dlg.FileName = "screenshot"

    If dlg.ShowDialog() = DialogResult.OK Then
        PictureBox1.Image.Save(dlg.FileName)
    End If
End Using

' Byte-Array speichern (z.B. heruntergeladenes PDF)
Using dlg As New SaveFileDialog()
    dlg.Filter = "PDF-Dateien (*.pdf)|*.pdf"

    If dlg.ShowDialog() = DialogResult.OK Then
        File.WriteAllBytes(dlg.FileName, pdfBytes)
    End If
End Using</pre>



<h2 class="wp-block-heading">Mit StreamWriter speichern (große Dateien)</h2>



<p>Für große Dateien oder zeilenweises Schreiben verwende einen <code>StreamWriter</code> mit dem Pfad aus dem Dialog:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using dlg As New SaveFileDialog()
    dlg.Filter = "CSV-Dateien (*.csv)|*.csv"

    If dlg.ShowDialog() = DialogResult.OK Then
        Using writer As New StreamWriter(dlg.FileName, False, Encoding.UTF8)
            writer.WriteLine("Name,Email,Alter")
            For Each contact In contacts
                writer.WriteLine($"{contact.Name},{contact.Email},{contact.Age}")
            Next
        End Using
    End If
End Using</pre>



<p>Der <code>StreamWriter</code>-Ansatz ist speichereffizienter für große Datenmengen, weil er Zeile für Zeile schreibt, statt den gesamten String im Speicher aufzubauen. Für einen tieferen Einblick in Dateioperationen siehe den <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>VB.NET Textdatei schreiben Guide</strong></a>.</p>



<h2 class="wp-block-heading">Alle wichtigen Eigenschaften im Überblick</h2>



<figure class="wp-block-table"><table><thead><tr><th>Eigenschaft</th><th>Standard</th><th>Zweck</th></tr></thead><tbody><tr><td><code>Filter</code></td><td>(leer)</td><td>Einträge im Dateityp-Dropdown</td></tr><tr><td><code>FilterIndex</code></td><td>1</td><td>Vorausgewählter Filter (1-basiert)</td></tr><tr><td><code>FileName</code></td><td>(leer)</td><td>Vorausgefüllter Dateiname / gewählter Pfad nach dem Dialog</td></tr><tr><td><code>InitialDirectory</code></td><td>(leer)</td><td>Startordner</td></tr><tr><td><code>DefaultExt</code></td><td>(leer)</td><td>Endung, die angehängt wird, wenn der Benutzer keine eingibt</td></tr><tr><td><code>AddExtension</code></td><td>True</td><td>Endung automatisch aus Filter anhängen</td></tr><tr><td><code>OverwritePrompt</code></td><td>True</td><td>Warnung vor dem Überschreiben bestehender Dateien</td></tr><tr><td><code>Title</code></td><td>&#8222;Speichern unter&#8220;</td><td>Fenstertitel des Dialogs</td></tr><tr><td><code>ValidateNames</code></td><td>True</td><td>Ungültige Dateinamenzeichen ablehnen</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Häufige Fehler</h2>



<h3 class="wp-block-heading">Schreiben ohne DialogResult zu prüfen</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - schreibt in leeren Pfad, wenn der Benutzer abbricht
dlg.ShowDialog()
File.WriteAllText(dlg.FileName, content)

' GUT - Ergebnis zuerst prüfen
If dlg.ShowDialog() = DialogResult.OK Then
    File.WriteAllText(dlg.FileName, content)
End If</pre>



<h3 class="wp-block-heading">Using-Block vergessen</h3>



<p>Der SaveFileDialog hält unverwaltete Ressourcen (ein Windows-COM-Objekt). Ohne <code>Using</code> bleiben diese Ressourcen im Speicher, bis der Garbage Collector läuft. Wickle ihn immer in einen <code>Using</code>-Block ein.</p>



<h3 class="wp-block-heading">Fehlerhafte Filter-Syntax</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - fehlendes Muster nach dem Pipe
dlg.Filter = "Textdateien|"

' SCHLECHT - Komma statt Pipe
dlg.Filter = "Textdateien (*.txt), *.txt"

' GUT - korrekte Beschreibung|Muster-Syntax
dlg.Filter = "Textdateien (*.txt)|*.txt"</pre>



<p>Ein fehlerhafter <code>Filter</code>-String wirft zur Laufzeit eine <code>ArgumentException</code>. Das Muster ist immer <code>Anzeigetext|*.endung</code>, mit einem Pipe-Zeichen als Trenner.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, von Dateioperationen bis zur fertigen Desktop-Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-savefile-de-1"><strong class="schema-faq-question"><strong>Wie öffne ich einen SaveFileDialog in VB.NET?</strong></strong> <p class="schema-faq-answer">Erstelle einen <code>New SaveFileDialog()</code> in einem <code>Using</code>-Block, setze die <code>Filter</code>-Eigenschaft und rufe <code>ShowDialog()</code> auf. Prüfe, ob das Ergebnis <code>DialogResult.OK</code> ist, bevor du in <code>dlg.FileName</code> schreibst.</p> </div> <div class="schema-faq-section" id="faq-savefile-de-2"><strong class="schema-faq-question"><strong>Wie setze ich einen Standard-Dateinamen im SaveFileDialog?</strong></strong> <p class="schema-faq-answer">Setze die <code>FileName</code>-Eigenschaft vor dem Aufruf von <code>ShowDialog()</code>. Beispiel: <code>dlg.FileName = "bericht.csv"</code>. Der Benutzer kann den Namen im Dialog noch ändern.</p> </div> <div class="schema-faq-section" id="faq-savefile-de-3"><strong class="schema-faq-question"><strong>Wie filtere ich Dateitypen im SaveFileDialog?</strong></strong> <p class="schema-faq-answer">Setze die <code>Filter</code>-Eigenschaft mit dem Muster <code>Beschreibung|*.endung</code>. Für mehrere Typen trenne sie mit Pipes: <code>"Text (*.txt)|*.txt|CSV (*.csv)|*.csv"</code>.</p> </div> <div class="schema-faq-section" id="faq-savefile-de-4"><strong class="schema-faq-question"><strong>Speichert der SaveFileDialog die Datei selbst?</strong></strong> <p class="schema-faq-answer">Nein. Der Dialog lässt den Benutzer nur einen Pfad und Dateinamen wählen. Du bist selbst dafür verantwortlich, die Datei zu schreiben, z.B. mit <code>File.WriteAllText()</code> oder <code>File.WriteAllBytes()</code> und dem Pfad aus <code>dlg.FileName</code>.</p> </div> <div class="schema-faq-section" id="faq-savefile-de-5"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen SaveFileDialog und OpenFileDialog?</strong></strong> <p class="schema-faq-answer">Der SaveFileDialog lässt den Benutzer ein Ziel für eine neue Datei wählen, mit eingebauter Überschreib-Bestätigung. Der OpenFileDialog lässt den Benutzer eine bestehende Datei zum Lesen auswählen. Beide geben den gewählten Pfad über die <code>FileName</code>-Eigenschaft zurück.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>Der <code>SaveFileDialog</code> gibt deiner VB.NET-Anwendung ein natives Datei-Speichern-Erlebnis mit minimalem Code. Setze einen <code>Filter</code> für Dateitypen, nutze <code>InitialDirectory</code> für den Startordner und prüfe immer <code>DialogResult.OK</code> bevor du schreibst. Für den eigentlichen Schreibvorgang verwende <code>File.WriteAllText()</code> für Text oder <code>File.WriteAllBytes()</code> für Binärdaten. Musst du stattdessen Dateien einlesen? Der OpenFileDialog funktioniert nach dem gleichen Muster in umgekehrter Richtung. Mehr zum Schreiben von Textdateien findest du im <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>VB.NET Textdatei schreiben Guide</strong></a>.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-savefiledialog/">VB.NET SaveFileDialog – Datei speichern mit Dialog (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-savefiledialog/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET DataTable – Erstellen, Füllen, Filtern (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-datatable/</link>
					<comments>https://robbelroot.de/blog/vbnet-datatable/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 20:04:34 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20459</guid>

					<description><![CDATA[<p>Die VB.NET DataTable speichert tabellarische Daten im Arbeitsspeicher, mit typisierten Spalten, zeilenweisem Zugriff und eingebautem Filtern. Sie ist das Rückgrat der Datenbindung in WinForms und die Brücke zwischen Datenbank und UI-Controls wie dem DataGridView. Dieser Guide behandelt Erstellung, Filtern, Sortieren, Datenbankanbindung und die häufigsten Fehler. Was ist eine DataTable und &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-datatable/">VB.NET DataTable – Erstellen, Füllen, Filtern (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Die <strong>VB.NET DataTable</strong> speichert tabellarische Daten im Arbeitsspeicher, mit typisierten Spalten, zeilenweisem Zugriff und eingebautem Filtern. Sie ist das Rückgrat der Datenbindung in WinForms und die Brücke zwischen Datenbank und UI-Controls wie dem DataGridView. Dieser Guide behandelt Erstellung, Filtern, Sortieren, Datenbankanbindung und die häufigsten Fehler.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">.NET-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du baust mehr als einen schnellen Prototyp?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Von Datenschichten bis zur kompletten Desktop-Anwendung kann ich helfen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Was ist eine DataTable und wann setzt man sie ein?</h2>



<p>Eine <code>DataTable</code> liegt im <code>System.Data</code>-Namespace und stellt eine einzelne Tabelle im Arbeitsspeicher dar. Vergleichbar mit einer Tabellenkalkulation: sie hat Spalten mit Namen und Typen, und Zeilen, die die eigentlichen Werte enthalten.</p>



<p>Verwende eine DataTable, wenn:</p>



<ul class="wp-block-list">
<li>Du <strong>tabellarische Daten an ein DataGridView</strong> oder andere WinForms-Controls binden willst</li>



<li>Du mit <strong>ADO.NET</strong> arbeitest und eine Tabelle aus einer Datenbankabfrage füllen willst</li>



<li>Du <strong>eingebautes Filtern und Sortieren</strong> brauchst, ohne eigene Logik schreiben zu müssen</li>



<li>Du <strong>CSV- oder Excel-Importe</strong> verarbeitest, bei denen Zeilen und Spalten natürlich abbildbar sind</li>
</ul>



<p>Falls du nur eine geordnete Liste von Objekten brauchst, ist eine <a href="https://robbelroot.de/blog/vbnet-list/"><strong>VB.NET List(Of T)</strong></a> einfacher und typsicherer. Für Key-Value-Lookups verwende ein <a href="https://robbelroot.de/blog/vb-net-dictionary-ein-kompletter-guide/"><strong>Dictionary</strong></a>. Die DataTable spielt ihre Stärken aus, wenn du eine flexible, schemabasierte Struktur mit Filtern, Sortieren und UI-Binding brauchst.</p>



<h2 class="wp-block-heading">Eine DataTable mit Spalten erstellen</h2>



<p>Jede DataTable beginnt mit einem Schema: den Spalten, die festlegen, welche Daten jede Zeile aufnehmen kann.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim table As New DataTable("Contacts")

' Spalten mit Name und Typ hinzufügen
table.Columns.Add("Id", GetType(Integer))
table.Columns.Add("Name", GetType(String))
table.Columns.Add("Email", GetType(String))
table.Columns.Add("Age", GetType(Integer))

' Primärschlüssel setzen
table.PrimaryKey = {table.Columns("Id")}</pre>



<p>Jede Spalte hat einen <code>DataType</code> (Integer, String, DateTime, Decimal, Boolean, etc.) und einen optionalen <code>ColumnName</code>. Der Primärschlüssel ermöglicht schnelle Lookups mit <code>Rows.Find()</code> und verhindert doppelte Einträge.</p>



<h3 class="wp-block-heading">Spalteneigenschaften</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Auto-Increment Spalte
Dim idCol = table.Columns("Id")
idCol.AutoIncrement = True
idCol.AutoIncrementSeed = 1
idCol.AutoIncrementStep = 1

' Standardwert
table.Columns("Age").DefaultValue = 0

' Nullwerte verbieten
table.Columns("Name").AllowDBNull = False</pre>



<h2 class="wp-block-heading">Zeilen hinzufügen</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Methode 1: NewRow + Felder zuweisen
Dim row As DataRow = table.NewRow()
row("Name") = "Alice"
row("Email") = "alice@example.com"
row("Age") = 30
table.Rows.Add(row)

' Methode 2: Werte direkt übergeben (Spaltenreihenfolge)
table.Rows.Add(Nothing, "Bob", "bob@example.com", 25)

' Methode 3: Aus einem Object-Array
Dim values() As Object = {Nothing, "Clara", "clara@example.com", 35}
table.Rows.Add(values)</pre>



<p>Bei einer <code>AutoIncrement</code>-Id-Spalte übergibst du <code>Nothing</code> für das Feld. Die DataTable vergibt den nächsten Wert automatisch.</p>



<h2 class="wp-block-heading">Daten lesen und zugreifen</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Auf eine bestimmte Zeile per Index zugreifen
Dim firstRow As DataRow = table.Rows(0)
Dim name As String = CStr(firstRow("Name"))

' Alle Zeilen durchlaufen
For Each row As DataRow In table.Rows
    Console.WriteLine($"{row("Id")}: {row("Name")} ({row("Email")})")
Next

' Zeile per Primärschlüssel finden
Dim found As DataRow = table.Rows.Find(2)
If found IsNot Nothing Then
    Console.WriteLine($"Gefunden: {found("Name")}")
End If

' Gesamtanzahl der Zeilen
Dim count As Integer = table.Rows.Count</pre>



<p>Felder geben <code>Object</code> zurück, daher musst du sie casten (<code>CStr</code>, <code>CInt</code>, <code>CDec</code>, etc.) oder die typisierte <code>Field(Of T)</code>-Erweiterungsmethode verwenden: <code>row.Field(Of String)("Name")</code>. Die <code>Field</code>-Methode behandelt <code>DBNull</code> bei Nullable-Typen automatisch sicher.</p>



<h2 class="wp-block-heading">Filtern mit Select und DataView</h2>



<p>DataTable bietet zwei Wege zum Filtern: die <code>Select()</code>-Methode für schnelle Abfragen und <code>DataView</code> für persistente, bindbare Filter.</p>



<h3 class="wp-block-heading">DataTable.Select()</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Nach Bedingung filtern
Dim olderThan25() As DataRow = table.Select("Age > 25")

' Filtern + sortieren
Dim sorted() As DataRow = table.Select("Age > 25", "Name ASC")

' Mehrere Bedingungen
Dim specific() As DataRow = table.Select("Age > 20 AND Name LIKE 'A%'")

' Ergebnisse verarbeiten
For Each row In olderThan25
    Console.WriteLine(row("Name"))
Next</pre>



<p>Der Filterausdruck nutzt eine SQL-ähnliche Syntax: <code>=</code>, <code>&lt;&gt;</code>, <code>&gt;</code>, <code>&lt;</code>, <code>LIKE</code>, <code>AND</code>, <code>OR</code>, <code>IN</code>, <code>IS NULL</code>. Der Sortierausdruck nimmt einen Spaltennamen gefolgt von <code>ASC</code> oder <code>DESC</code>.</p>



<h3 class="wp-block-heading">DataView für bindbares Filtern</h3>



<p>Eine <code>DataView</code> umschließt eine DataTable und liefert eine gefilterte, sortierte Sicht, die direkt an UI-Controls gebunden werden kann:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim view As New DataView(table)
view.RowFilter = "Age >= 30"
view.Sort = "Name ASC"

' An DataGridView binden
DataGridView1.DataSource = view

' Filter zur Laufzeit ändern (UI aktualisiert sich automatisch)
view.RowFilter = "Name LIKE 'B%'"</pre>



<p>DataView ist die bessere Wahl für eine <a href="https://robbelroot.de/blog/ein-vb-net-datagridview-fuellen/"><strong>DataGridView-Filterfunktion</strong></a>, weil sie das gebundene Control automatisch aktualisiert, wenn <code>RowFilter</code> oder <code>Sort</code> geändert werden.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du eine skalierbare .NET-Datenschicht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von DataTables bis zur kompletten Anwendungsarchitektur: Ich entwerfe Software, die hält. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Zeilen sortieren</h2>



<p>Die DataTable selbst hat keine <code>Sort()</code>-Methode. Sortiert wird über <code>Select()</code> oder <code>DataView</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Sortieren mit Select (gibt DataRow-Array zurück)
Dim sortedRows() As DataRow = table.Select("", "Age DESC")

' Sortieren mit DataView (bindbar)
Dim view As New DataView(table)
view.Sort = "Name ASC, Age DESC"

' Sortieren mit LINQ (gibt neue Collection zurück)
Dim linqSorted = From row In table.AsEnumerable()
                 Order By row.Field(Of String)("Name")
                 Select row</pre>



<p>Für DataGridView-Binding verwende DataView. Zum Verarbeiten von Zeilen im Code funktionieren die <code>Select()</code>-Methode und LINQ gleich gut.</p>



<h2 class="wp-block-heading">Zeilen aktualisieren und löschen</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Feld aktualisieren
table.Rows(0)("Email") = "alice.new@example.com"

' Per Primärschlüssel aktualisieren
Dim target As DataRow = table.Rows.Find(2)
If target IsNot Nothing Then
    target("Age") = 26
End If

' Zeile löschen (markiert sie als gelöscht)
table.Rows(0).Delete()

' Zeile sofort entfernen
table.Rows.Remove(table.Rows(0))

' Alle ausstehenden Änderungen übernehmen
table.AcceptChanges()</pre>



<p>Wichtiger Unterschied: <code>Delete()</code> markiert die Zeile mit <code>RowState = Deleted</code>, behält sie aber in der Tabelle, bis <code>AcceptChanges()</code> aufgerufen wird. <code>Remove()</code> löscht die Zeile sofort. Verwende <code>Delete()</code>, wenn du Change Tracking brauchst (z.B. beim Zurückschreiben in die Datenbank mit einem DataAdapter).</p>



<h2 class="wp-block-heading">DataTable an ein DataGridView binden</h2>



<p>Einer der häufigsten Einsatzzwecke einer DataTable ist die Anzeige in einem <a href="https://robbelroot.de/blog/ein-vb-net-datagridview-fuellen/"><strong>DataGridView</strong></a>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Direkte Bindung
DataGridView1.DataSource = table

' Bindung über DataView (mit Filter + Sortierung)
Dim view As New DataView(table)
view.RowFilter = "Age > 25"
view.Sort = "Name ASC"
DataGridView1.DataSource = view</pre>



<p>Das DataGridView generiert die Spalten automatisch aus dem DataTable-Schema. Änderungen im Grid werden automatisch in die DataTable zurückgeschrieben. Für ein schreibgeschütztes Grid setze <code>DataGridView1.ReadOnly = True</code>.</p>



<h3 class="wp-block-heading">Grid nach Datenänderungen aktualisieren</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Zeile programmatisch hinzufügen
table.Rows.Add(Nothing, "David", "david@example.com", 28)

' Grid aktualisiert sich automatisch bei gebundener DataTable
' Kein manuelles Refresh nötig

' Wenn du die gesamte DataTable austauschst, binde sie neu
DataGridView1.DataSource = Nothing
DataGridView1.DataSource = newTable</pre>



<h2 class="wp-block-heading">Daten aus einer Datenbank laden</h2>



<p>DataTable funktioniert mit jedem ADO.NET-Provider. Hier ein Beispiel mit <a href="https://robbelroot.de/blog/vbnet-sqlite/"><strong>SQLite</strong></a>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports System.Data.SQLite

Dim table As New DataTable()

Using connection As New SQLiteConnection("Data Source=app.db")
    connection.Open()
    Using command As New SQLiteCommand("SELECT * FROM Contacts", connection)
        Using reader As SQLiteDataReader = command.ExecuteReader()
            table.Load(reader)
        End Using
    End Using
End Using

' table enthält jetzt alle Zeilen der Contacts-Tabelle
DataGridView1.DataSource = table</pre>



<p>Die <code>Load()</code>-Methode liest alle Zeilen aus einem DataReader und erstellt die Spalten automatisch anhand des Abfrageergebnisses. Das funktioniert mit SQL Server, MySQL, PostgreSQL und jedem anderen ADO.NET-Provider.</p>



<h3 class="wp-block-heading">Alternative: DataAdapter verwenden</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim table As New DataTable()

Using connection As New SQLiteConnection("Data Source=app.db")
    Using adapter As New SQLiteDataAdapter("SELECT * FROM Contacts", connection)
        adapter.Fill(table)
    End Using
End Using</pre>



<p>Der DataAdapter-Ansatz ist kürzer und unterstützt auch das Zurückschreiben von Änderungen in die Datenbank mit <code>adapter.Update(table)</code>. Für einfacheren, stark typisierten Datenbankzugriff ohne DataTable ist <a href="https://robbelroot.de/blog/vbnet-dapper/"><strong>Dapper</strong></a> eine Alternative.</p>



<h2 class="wp-block-heading">Konvertierung zwischen DataTable und List</h2>



<p>Manchmal muss man zwischen einer DataTable und einer typisierten <a href="https://robbelroot.de/blog/vbnet-list/"><strong>List(Of T)</strong></a> wechseln:</p>



<h3 class="wp-block-heading">DataTable zu List(Of T)</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Class Contact
    Public Property Id As Integer
    Public Property Name As String
    Public Property Email As String
    Public Property Age As Integer
End Class

' DataTable-Zeilen in typisierte Liste konvertieren
Dim contacts = table.AsEnumerable().Select(Function(row)
    Return New Contact With {
        .Id = row.Field(Of Integer)("Id"),
        .Name = row.Field(Of String)("Name"),
        .Email = row.Field(Of String)("Email"),
        .Age = row.Field(Of Integer)("Age")
    }
End Function).ToList()</pre>



<h3 class="wp-block-heading">List(Of T) zu DataTable</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Function ToDataTable(contacts As List(Of Contact)) As DataTable
    Dim table As New DataTable()
    table.Columns.Add("Id", GetType(Integer))
    table.Columns.Add("Name", GetType(String))
    table.Columns.Add("Email", GetType(String))
    table.Columns.Add("Age", GetType(Integer))

    For Each c In contacts
        table.Rows.Add(c.Id, c.Name, c.Email, c.Age)
    Next

    Return table
End Function</pre>



<p>Der LINQ-Ansatz mit <code>AsEnumerable()</code> erfordert einen Verweis auf <code>System.Data.DataSetExtensions</code>. Im modernen .NET (5+) ist dieser standardmäßig enthalten.</p>



<h2 class="wp-block-heading">Häufige Stolperfallen</h2>



<h3 class="wp-block-heading">DBNull ignorieren</h3>



<p>DataTable-Felder können <code>DBNull.Value</code> statt <code>Nothing</code> enthalten. Ein direkter Cast wirft dann eine <code>InvalidCastException</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - wirft InvalidCastException wenn Email DBNull ist
Dim email As String = CStr(row("Email"))

' GUT - erst auf DBNull prüfen
Dim email As String = If(row.IsNull("Email"), "", CStr(row("Email")))

' OPTIMAL - typisierte Field-Erweiterung verwenden
Dim email As String = row.Field(Of String)("Email")  ' gibt Nothing zurück bei DBNull</pre>



<h3 class="wp-block-heading">Zeilen in einer For-Each-Schleife löschen</h3>



<p>Genau wie bei einer <a href="https://robbelroot.de/blog/vbnet-list/"><strong>List</strong></a> wirft das Ändern einer DataTable während der Iteration eine Exception. Verwende eine rückwärts laufende <code>For</code>-Schleife oder sammle die Zeilen zuerst:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - Änderung während Iteration
For Each row As DataRow In table.Rows
    If CInt(row("Age")) &lt; 18 Then
        row.Delete()
    End If
Next

' GUT - rückwärts iterieren
For i As Integer = table.Rows.Count - 1 To 0 Step -1
    If CInt(table.Rows(i)("Age")) &lt; 18 Then
        table.Rows(i).Delete()
    End If
Next
table.AcceptChanges()</pre>



<h3 class="wp-block-heading">AcceptChanges vergessen</h3>



<p>Wenn du <code>Delete()</code> auf eine Zeile aufrufst, wird sie nur als gelöscht markiert. Die Zeile erscheint weiterhin in <code>table.Rows.Count</code> und kann unerwartetes Verhalten verursachen. Rufe <code>AcceptChanges()</code> nach einer Reihe von Löschungen auf, oder verwende <code>Remove()</code> für sofortiges Entfernen.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, von sauberen Datenschichten bis zur fertigen Desktop-Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-datatable-de-1"><strong class="schema-faq-question"><strong>Wie erstelle ich eine DataTable in VB.NET?</strong></strong> <p class="schema-faq-answer">Erstelle sie mit <code>Dim table As New DataTable()</code>, füge Spalten hinzu mit <code>table.Columns.Add("Name", GetType(String))</code> und Zeilen mit <code>table.Rows.Add(werte)</code>. Jede Spalte braucht einen Namen und einen Datentyp.</p> </div> <div class="schema-faq-section" id="faq-datatable-de-2"><strong class="schema-faq-question"><strong>Wie filtere ich eine DataTable in VB.NET?</strong></strong> <p class="schema-faq-answer">Verwende <code>table.Select("Age > 25")</code> für schnelle Abfragen, die ein DataRow-Array zurückgeben. Für persistente, bindbare Filter erstelle eine DataView mit <code>view.RowFilter = "Age > 25"</code> und binde sie an dein DataGridView.</p> </div> <div class="schema-faq-section" id="faq-datatable-de-3"><strong class="schema-faq-question"><strong>Wie binde ich eine DataTable an ein DataGridView?</strong></strong> <p class="schema-faq-answer">Setze <code>DataGridView1.DataSource = table</code>. Das Grid generiert die Spalten automatisch aus dem Tabellen-Schema. Für gefilterte Ansichten binde stattdessen eine DataView: <code>DataGridView1.DataSource = New DataView(table)</code>.</p> </div> <div class="schema-faq-section" id="faq-datatable-de-4"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen DataTable und List(Of T)?</strong></strong> <p class="schema-faq-answer">Eine DataTable speichert untypisierte Zeilen mit Spalten, die zur Laufzeit definiert werden, unterstützt SQL-ähnliches Filtern und bindet nativ an DataGridView. Eine List(Of T) hält stark typisierte Objekte, ist einfacher zu nutzen, erfordert aber manuelles Filtern mit LINQ.</p> </div> <div class="schema-faq-section" id="faq-datatable-de-5"><strong class="schema-faq-question"><strong>Wie lade ich Datenbankdaten in eine DataTable?</strong></strong> <p class="schema-faq-answer">Verwende <code>table.Load(reader)</code> mit einem beliebigen ADO.NET DataReader, oder einen DataAdapter mit <code>adapter.Fill(table)</code>. Beide Ansätze erstellen die Spalten automatisch aus dem Abfrageergebnis.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>Die <code>DataTable</code> ist die richtige Wahl, wenn du schemabasierte, filterbare Tabellendaten mit nativer DataGridView-Bindung brauchst. Verwende <code>Select()</code> für schnelle Abfragen, <code>DataView</code> für live-gefilterte UI-Bindung und <code>Field(Of T)</code> zur sicheren DBNull-Behandlung. Für einfachere Anwendungsfälle mit typisierten Objekten ist eine <a href="https://robbelroot.de/blog/vbnet-list/"><strong>List(Of T)</strong></a> oft die bessere Wahl. Für Datenbankzugriff ohne DataTable schau dir <a href="https://robbelroot.de/blog/vbnet-dapper/"><strong>Dapper</strong></a> an.</p>



<p></p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-datatable/">VB.NET DataTable – Erstellen, Füllen, Filtern (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-datatable/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET List – Erstellen, Sortieren, Filtern (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-list/</link>
					<comments>https://robbelroot.de/blog/vbnet-list/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 14:20:33 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20446</guid>

					<description><![CDATA[<p>Die VB.NET List ist eine der meistgenutzten Datenstrukturen in der .NET-Entwicklung. Sie speichert Objekte in einer geordneten, dynamisch wachsenden Collection und bietet Methoden zum Hinzufügen, Entfernen, Sortieren und Suchen mit minimalem Code. Dieser Guide deckt alles ab: von der Erstellung über LINQ-Abfragen bis hin zu typischen Stolperfallen. Was ist eine &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-list/">VB.NET List – Erstellen, Sortieren, Filtern (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Die <strong>VB.NET List</strong> ist eine der meistgenutzten Datenstrukturen in der .NET-Entwicklung. Sie speichert Objekte in einer geordneten, dynamisch wachsenden Collection und bietet Methoden zum Hinzufügen, Entfernen, Sortieren und Suchen mit minimalem Code. Dieser Guide deckt alles ab: von der Erstellung über LINQ-Abfragen bis hin zu typischen Stolperfallen.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">.NET-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du baust mehr als nur eine Liste?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Von Datenstrukturen bis zur kompletten Anwendungsarchitektur kann ich helfen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Was ist eine List(Of T) und wann setzt man sie ein?</h2>



<p>Eine <code>List(Of T)</code> ist eine generische Collection aus dem <code>System.Collections.Generic</code>-Namespace. Das <code>T</code> steht für den Typ der gespeicherten Objekte: <code>List(Of String)</code> speichert Strings, <code>List(Of Integer)</code> Zahlen, <code>List(Of Customer)</code> eigene Objekte.</p>



<p>Verwende eine List, wenn:</p>



<ul class="wp-block-list">
<li>Du eine <strong>geordnete</strong> Sammlung brauchst, in der Elemente eine Position (Index) haben</li>



<li>Die <strong>Anzahl der Elemente sich zur Laufzeit ändert</strong> (anders als bei Arrays, die eine feste Größe haben)</li>



<li>Du eingebaute Methoden zum <strong>Sortieren, Suchen und Filtern</strong> brauchst</li>



<li>Du Elemente <strong>nach Position</strong> abrufst, nicht nach einem Schlüssel</li>
</ul>



<p>Wenn du stattdessen Key-Value-Lookups brauchst (z.B. einen Kunden per ID finden), verwende ein <a href="https://robbelroot.de/blog/vb-net-dictionary-ein-kompletter-guide/"><strong>VB.NET Dictionary</strong></a>. Listen durchsuchen jedes Element der Reihe nach, was bei großen Datenmengen langsam wird. Dictionaries finden Einträge in konstanter Zeit.</p>



<h2 class="wp-block-heading">Eine List erstellen</h2>



<p>Die gängigsten Wege, eine <code>List(Of T)</code> zu erstellen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Leere Liste
Dim names As New List(Of String)

' Liste mit Startwerten
Dim numbers As New List(Of Integer) From {3, 5, 7, 9}

' Liste mit eigenen Objekten
Dim customers As New List(Of Customer) From {
    New Customer With {.Name = "Alice", .Email = "alice@example.com"},
    New Customer With {.Name = "Bob", .Email = "bob@example.com"}
}</pre>



<p>Das <code>From</code>-Keyword zusammen mit den geschweiften Klammern ist ein Collection Initializer. Im Hintergrund wird für jedes Element <code>Add()</code> aufgerufen.</p>



<h3 class="wp-block-heading">Initiale Kapazität setzen</h3>



<p>Wenn du ungefähr weißt, wie viele Elemente die Liste aufnehmen wird, setze die Kapazität im Voraus. Das vermeidet wiederholtes internes Array-Resizing:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Platz für ca. 500 Elemente vorbelegen
Dim largeList As New List(Of String)(500)</pre>



<p>Das begrenzt die Liste nicht auf 500 Einträge. Es vermeidet nur unnötige Speicher-Allokationen, bis du diese Zahl überschreitest.</p>



<h2 class="wp-block-heading">Elemente hinzufügen</h2>



<h3 class="wp-block-heading">Add und AddRange</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim names As New List(Of String)

' Einzelne Elemente hinzufügen
names.Add("Alice")
names.Add("Bob")

' Mehrere Elemente auf einmal
names.AddRange({"Clara", "David", "Eva"})

' Elemente aus einer anderen Liste
Dim moreNames As New List(Of String) From {"Frank", "Grace"}
names.AddRange(moreNames)</pre>



<h3 class="wp-block-heading">An einer bestimmten Position einfügen</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' "Zara" an Position 0 einfügen (Anfang)
names.Insert(0, "Zara")

' An Position 2 einfügen
names.Insert(2, "Maria")</pre>



<p>Beachte, dass <code>Insert()</code> alle nachfolgenden Elemente verschiebt, was O(n) kostet. Für häufige Einfügungen am Anfang ist eine <code>LinkedList(Of T)</code> besser geeignet.</p>



<h2 class="wp-block-heading">Auf Elemente zugreifen</h2>



<p>Der Zugriff erfolgt über den nullbasierten Index:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim names As New List(Of String) From {"Alice", "Bob", "Clara"}

' Zugriff per Index
Dim first As String = names(0)    ' "Alice"
Dim last As String = names(names.Count - 1)  ' "Clara"

' Mit For Each iterieren
For Each name In names
    Console.WriteLine(name)
Next

' Mit Index iterieren
For i As Integer = 0 To names.Count - 1
    Console.WriteLine($"[{i}] {names(i)}")
Next</pre>



<p>Ein ungültiger Index wirft eine <code>ArgumentOutOfRangeException</code>. Prüfe immer <code>Count</code>, bevor du einen bestimmten Index verwendest, oder nutze LINQ-Methoden wie <code>FirstOrDefault()</code>.</p>



<h2 class="wp-block-heading">Elemente entfernen</h2>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim names As New List(Of String) From {"Alice", "Bob", "Clara", "David"}

' Nach Wert entfernen (erstes Vorkommen)
names.Remove("Bob")   ' gibt True zurück wenn gefunden

' Nach Index entfernen
names.RemoveAt(0)      ' entfernt "Alice"

' Letztes Element entfernen
If names.Count > 0 Then
    names.RemoveAt(names.Count - 1)
End If

' Alle Elemente entfernen, die eine Bedingung erfüllen
names.RemoveAll(Function(n) n.StartsWith("C"))

' Alles leeren
names.Clear()</pre>



<p><code>Remove()</code> durchsucht die Liste von vorne und entfernt den ersten Treffer. Wenn das Element nicht existiert, gibt die Methode <code>False</code> zurück, ohne eine Exception zu werfen. <code>RemoveAt()</code> bei einem ungültigen Index wirft hingegen eine Exception.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du eine skalierbare .NET-Anwendung?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von Datenstrukturen bis zur kompletten Desktop-Anwendung: Ich entwerfe Software, die hält. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Eine Liste sortieren</h2>



<h3 class="wp-block-heading">Einfache Sortierung</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim names As New List(Of String) From {"Clara", "Alice", "Bob"}

' Alphabetisch sortieren (in-place)
names.Sort()
' Ergebnis: Alice, Bob, Clara

' Reihenfolge umkehren
names.Reverse()
' Ergebnis: Clara, Bob, Alice</pre>



<h3 class="wp-block-heading">Eigene Sortierreihenfolge</h3>



<p>Für eigene Objekte übergibst du einen Vergleichs-Lambda an <code>Sort()</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Class Contact
    Public Property Name As String
    Public Property Age As Integer
End Class

Dim contacts As New List(Of Contact) From {
    New Contact With {.Name = "Clara", .Age = 30},
    New Contact With {.Name = "Alice", .Age = 25},
    New Contact With {.Name = "Bob", .Age = 35}
}

' Nach Name sortieren
contacts.Sort(Function(a, b) String.Compare(a.Name, b.Name))

' Nach Alter absteigend sortieren
contacts.Sort(Function(a, b) b.Age.CompareTo(a.Age))</pre>



<h3 class="wp-block-heading">Sortieren mit LINQ (nicht-destruktiv)</h3>



<p><code>Sort()</code> verändert die Originalliste. Wenn du eine neue sortierte Liste willst, ohne das Original zu ändern, verwende LINQ:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Original bleibt unverändert
Dim sorted = contacts.OrderBy(Function(c) c.Name).ToList()
Dim sortedDesc = contacts.OrderByDescending(Function(c) c.Age).ToList()</pre>



<h2 class="wp-block-heading">Suchen und Filtern mit LINQ</h2>



<p>LINQ ist der mächtigste Weg, Listen in VB.NET abzufragen. Importiere <code>System.Linq</code> (ist standardmäßig importiert) und du bekommst ein volles Set an Abfragemethoden:</p>



<h3 class="wp-block-heading">Elemente finden</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim contacts As New List(Of Contact) From {
    New Contact With {.Name = "Alice", .Age = 25},
    New Contact With {.Name = "Bob", .Age = 35},
    New Contact With {.Name = "Clara", .Age = 30}
}

' Ersten Treffer finden (gibt Nothing zurück wenn nicht gefunden)
Dim alice = contacts.FirstOrDefault(Function(c) c.Name = "Alice")

' Prüfen ob irgendein Element passt
Dim hasOlderThan30 As Boolean = contacts.Any(Function(c) c.Age > 30)

' Prüfen ob alle Elemente passen
Dim allAdults As Boolean = contacts.All(Function(c) c.Age >= 18)</pre>



<h3 class="wp-block-heading">Elemente filtern</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Alle Kontakte älter als 25
Dim olderContacts = contacts.Where(Function(c) c.Age > 25).ToList()

' Nur die Namen extrahieren
Dim names = contacts.Select(Function(c) c.Name).ToList()

' Kombiniert: filtern + transformieren
Dim olderNames = contacts _
    .Where(Function(c) c.Age > 25) _
    .Select(Function(c) c.Name) _
    .ToList()</pre>



<h3 class="wp-block-heading">Aggregat-Abfragen</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Count, Min, Max, Average, Sum
Dim count As Integer = contacts.Count
Dim youngest As Integer = contacts.Min(Function(c) c.Age)
Dim oldest As Integer = contacts.Max(Function(c) c.Age)
Dim averageAge As Double = contacts.Average(Function(c) c.Age)

' Unique Werte
Dim uniqueAges = contacts.Select(Function(c) c.Age).Distinct().ToList()</pre>



<h2 class="wp-block-heading">Listen konvertieren</h2>



<p>Listen lassen sich in andere Collection-Typen umwandeln und umgekehrt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Liste zu Array
Dim namesArray As String() = names.ToArray()

' Array zu Liste
Dim backToList As List(Of String) = namesArray.ToList()

' Liste zu Dictionary (Schlüssel muss eindeutig sein)
Dim contactDict = contacts.ToDictionary(
    Function(c) c.Name,
    Function(c) c)

' String aus Liste (zusammenfügen)
Dim csv As String = String.Join(", ", names)
' Ergebnis: "Alice, Bob, Clara"</pre>



<p>Die <code>ToDictionary()</code>-Konvertierung ist besonders nützlich, wenn du später schnelle Lookups per Schlüssel brauchst. Mehr dazu im <a href="https://robbelroot.de/blog/vb-net-dictionary-ein-kompletter-guide/"><strong>Dictionary Guide</strong></a>.</p>



<h2 class="wp-block-heading">List vs. Array vs. Dictionary</h2>



<p>Die Wahl der richtigen Collection ist entscheidend für Lesbarkeit und Performance. Hier ein Vergleich der gängigsten Typen:</p>



<figure class="wp-block-table"><table><thead><tr><th></th><th>List(Of T)</th><th>Array</th><th>Dictionary(Of TKey, TValue)</th></tr></thead><tbody><tr><td><strong>Größe</strong></td><td>Dynamisch</td><td>Fest</td><td>Dynamisch</td></tr><tr><td><strong>Zugriff per Index</strong></td><td>O(1)</td><td>O(1)</td><td>N/A</td></tr><tr><td><strong>Zugriff per Schlüssel</strong></td><td>O(n)</td><td>O(n)</td><td>O(1)</td></tr><tr><td><strong>Element hinzufügen</strong></td><td>O(1) amortisiert</td><td>N/A (feste Größe)</td><td>O(1) amortisiert</td></tr><tr><td><strong>Element entfernen</strong></td><td>O(n)</td><td>N/A</td><td>O(1)</td></tr><tr><td><strong>Ideal für</strong></td><td>Geordnete Sammlungen, Iteration</td><td>Buffer fester Größe, Interop</td><td>Key-Value-Lookups</td></tr></tbody></table></figure>



<p>Einen detaillierten Performance-Vergleich mit echten Benchmarks findest du im <a href="https://robbelroot.de/blog/csharp-list-the-ultimate-guide/"><strong>C# List Guide</strong></a>. Die Ergebnisse gelten genauso für VB.NET, da beide die gleiche .NET-Runtime verwenden.</p>



<h2 class="wp-block-heading">Häufige Stolperfallen</h2>



<h3 class="wp-block-heading">Liste während der Iteration ändern</h3>



<p>Das ist einer der häufigsten Anfängerfehler. Elemente innerhalb einer <code>For Each</code>-Schleife zu entfernen wirft eine <code>InvalidOperationException</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' SCHLECHT - wirft InvalidOperationException!
For Each name In names
    If name.StartsWith("A") Then
        names.Remove(name)
    End If
Next

' GUT - RemoveAll verwenden
names.RemoveAll(Function(n) n.StartsWith("A"))

' EBENFALLS GUT - rückwärts mit For iterieren
For i As Integer = names.Count - 1 To 0 Step -1
    If names(i).StartsWith("A") Then
        names.RemoveAt(i)
    End If
Next</pre>



<h3 class="wp-block-heading">Liste für Lookups verwenden</h3>



<p>Wenn du häufig Elemente nach einer eindeutigen Eigenschaft suchst (Name, ID, E-Mail), ist eine <code>List</code> die falsche Wahl. Jede Suche iteriert die gesamte Liste. Ein <code>Dictionary</code> findet das Element sofort. Der Unterschied wird bei Tausenden Einträgen massiv, wie in diesem <a href="https://robbelroot.de/blog/csharp-list-the-ultimate-guide/"><strong>Benchmark-Vergleich</strong></a> gezeigt.</p>



<h3 class="wp-block-heading">ToList() vergessen</h3>



<p>LINQ-Methoden wie <code>Where()</code> und <code>Select()</code> geben lazy <code>IEnumerable</code>-Objekte zurück, keine Listen. Jedes Mal wenn du iterierst, wird die Abfrage erneut ausgeführt. Ruf <code>.ToList()</code> auf, um das Ergebnis zu materialisieren:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Lazy - führt den Filter zweimal aus!
Dim filtered = names.Where(Function(n) n.Length > 3)
Console.WriteLine(filtered.Count())   ' Filter läuft hier
Console.WriteLine(filtered.Count())   ' Filter läuft nochmal

' Besser - einmal materialisieren
Dim filteredList = names.Where(Function(n) n.Length > 3).ToList()
Console.WriteLine(filteredList.Count)  ' liest nur den Count
Console.WriteLine(filteredList.Count)  ' gleich, keine Neuauswertung</pre>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, von sauberen Datenstrukturen bis zur fertigen Desktop-Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-list-de-1"><strong class="schema-faq-question"><strong>Wie erstelle ich eine Liste in VB.NET?</strong></strong> <p class="schema-faq-answer">Verwende <code>Dim myList As New List(Of String)</code> für eine leere Liste oder <code>Dim myList As New List(Of String) From {"Alice", "Bob"}</code> mit Startwerten. Ersetze <code>String</code> durch den Typ, den du brauchst.</p> </div> <div class="schema-faq-section" id="faq-list-de-2"><strong class="schema-faq-question"><strong>Was ist der Unterschied zwischen List und Array in VB.NET?</strong></strong> <p class="schema-faq-answer">Arrays haben eine feste Größe, die bei der Erstellung festgelegt wird. Listen wachsen und schrumpfen dynamisch mit Methoden wie <code>Add()</code> und <code>Remove()</code>. Verwende Arrays für Buffer fester Größe, Listen wenn sich die Anzahl ändern kann.</p> </div> <div class="schema-faq-section" id="faq-list-de-3"><strong class="schema-faq-question"><strong>Wie sortiere ich eine Liste in VB.NET?</strong></strong> <p class="schema-faq-answer">Rufe <code>myList.Sort()</code> für die Standardsortierung auf. Für eigene Objekte verwende ein Lambda: <code>myList.Sort(Function(a, b) a.Name.CompareTo(b.Name))</code>. LINQ <code>OrderBy()</code> erstellt eine neue Liste, ohne das Original zu ändern.</p> </div> <div class="schema-faq-section" id="faq-list-de-4"><strong class="schema-faq-question"><strong>Wie entferne ich Elemente aus einer VB.NET Liste?</strong></strong> <p class="schema-faq-answer">Verwende <code>Remove(item)</code> zum Entfernen nach Wert, <code>RemoveAt(index)</code> nach Position oder <code>RemoveAll(Function(x) bedingung)</code> für alle passenden Elemente. Entferne nie Elemente innerhalb einer <code>For Each</code>-Schleife.</p> </div> <div class="schema-faq-section" id="faq-list-de-5"><strong class="schema-faq-question"><strong>Wann sollte ich ein Dictionary statt einer Liste verwenden?</strong></strong> <p class="schema-faq-answer">Verwende ein Dictionary immer wenn du Elemente nach einem eindeutigen Schlüssel (Name, ID, E-Mail) suchen musst. Eine Liste muss jeden Eintrag durchlaufen (O(n)), während ein Dictionary in konstanter Zeit findet (O(1)).</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>Die <code>List(Of T)</code> ist die Standard-Collection für geordnete, dynamische Daten in VB.NET. Verwende <code>Add()</code> und <code>Remove()</code> für Grundoperationen, <code>Sort()</code> mit einem Lambda für eigene Sortierung und LINQ für Filtern und Transformieren. Für schlüsselbasierte Lookups wechsle zum <a href="https://robbelroot.de/blog/vb-net-dictionary-ein-kompletter-guide/"><strong>Dictionary</strong></a>. Die gleichen Konzepte gelten auch für C# mit leicht anderer Syntax, wie im <a href="https://robbelroot.de/blog/csharp-list-the-ultimate-guide/"><strong>C# List Guide</strong></a> gezeigt.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-list/">VB.NET List – Erstellen, Sortieren, Filtern (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-list/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET Dapper – Micro ORM für sauberen Datenzugriff (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-dapper/</link>
					<comments>https://robbelroot.de/blog/vbnet-dapper/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 08 Apr 2026 10:00:53 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20441</guid>

					<description><![CDATA[<p>Dapper ist der schnellste Weg, um das mühsame SqliteCommand-Boilerplate in deiner VB.NET-Anwendung durch sauberen, typsicheren Datenzugriff zu ersetzen. In diesem Guide zeige ich dir, wie du Dapper per NuGet installierst, Abfrageergebnisse direkt auf Klassen mappst und alle CRUD-Operationen mit minimalem Code ausführst. Wenn du bisher AddWithValue und ExecuteReader von Hand &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-dapper/">VB.NET Dapper – Micro ORM für sauberen Datenzugriff (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>Dapper</strong> ist der schnellste Weg, um das mühsame <code>SqliteCommand</code>-Boilerplate in deiner <strong>VB.NET</strong>-Anwendung durch sauberen, typsicheren Datenzugriff zu ersetzen. In diesem Guide zeige ich dir, wie du Dapper per NuGet installierst, Abfrageergebnisse direkt auf Klassen mappst und alle CRUD-Operationen mit minimalem Code ausführst. Wenn du bisher <code>AddWithValue</code> und <code>ExecuteReader</code> von Hand geschrieben hast, ist das hier dein nächster Schritt.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Datenbank-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">ADO.NET-Boilerplate ohne Ende?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich entwickle seit über 17 Jahren professionell in VB.NET und C#. Ob Dapper, EF Core oder Raw SQL &#8211; ich helfe dir, die richtige Data-Access-Strategie zu finden.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Was ist Dapper und warum lohnt es sich?</h2>



<p>Dapper ist ein leichtgewichtiger &#8222;Micro ORM&#8220; für .NET, der ursprünglich vom Stack Overflow-Team entwickelt wurde, um deren eigene Performance-Probleme zu lösen. Er setzt auf <code>IDbConnection</code> auf und erweitert es mit praktischen Methoden wie <code>Query(Of T)</code> und <code>Execute()</code>. Hier ist, warum das relevant ist:</p>



<ul class="wp-block-list">
<li><strong>Kein Boilerplate</strong> – kein manuelles <code>SqliteCommand</code>, <code>AddWithValue</code>, <code>ExecuteReader</code> und spaltenweises Mapping mehr</li>



<li><strong>Stark typisiert</strong> – Abfrageergebnisse werden direkt auf deine VB.NET-Klassen gemappt, anhand übereinstimmender Property-Namen</li>



<li><strong>Schnell</strong> – Dapper ist fast so schnell wie reines ADO.NET, deutlich schneller als Entity Framework bei einfachen Abfragen</li>



<li><strong>Keine Magie</strong> – du schreibst echtes SQL, also weißt du immer genau, was an die Datenbank geht</li>



<li><strong>Funktioniert mit jeder Datenbank</strong> – SQLite, SQL Server, PostgreSQL, MySQL, alles was eine <code>IDbConnection</code> hat</li>
</ul>



<p>Wenn du den <a href="https://robbelroot.de/blog/vbnet-sqlite/"><strong>VB.NET SQLite Artikel</strong></a> gelesen hast, kennst du bereits die Grundlagen: Datenbank erstellen und Abfragen mit <code>SqliteCommand</code> ausführen. Dapper ersetzt diese manuelle Arbeit, während du die volle Kontrolle über dein SQL behältst.</p>



<h2 class="wp-block-heading">Dapper per NuGet installieren</h2>



<p>Öffne die Package Manager Console in Visual Studio (<em>Tools → NuGet Package Manager → Package Manager Console</em>) und führe aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Install-Package Dapper
Install-Package Microsoft.Data.Sqlite</pre>



<p>Du brauchst beide Pakete: <code>Dapper</code> liefert die Extension Methods, <code>Microsoft.Data.Sqlite</code> die Datenbank-Verbindung. Wenn du <code>Microsoft.Data.Sqlite</code> aus einem früheren Projekt bereits installiert hast, reicht es, nur <code>Dapper</code> hinzuzufügen.</p>



<p>Alternativ: Rechtsklick auf das Projekt im Solution Explorer → <em>NuGet-Pakete verwalten</em> → nach <code>Dapper</code> suchen → Installieren. Dann für <code>Microsoft.Data.Sqlite</code> wiederholen, falls noch nicht vorhanden.</p>



<h2 class="wp-block-heading">Die Model-Klasse anlegen</h2>



<p>Bevor du Abfragen schreibst, definiere eine Klasse, deren Properties den Spaltennamen in deiner Tabelle entsprechen. Dapper mappt Spalten auf Properties anhand des Namens (Groß-/Kleinschreibung egal):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Class Contact
    Public Property Id As Long
    Public Property Name As String
    Public Property Email As String
    Public Property Phone As String
    Public Property CreatedAt As String
End Class</pre>



<p>Das ist alles, was Dapper braucht. Keine Attribute, keine Basisklassen, keine Konfigurationsdateien. Wenn ein Spaltenname nicht zum Property-Namen passt, verwende einen SQL-Alias: <code>SELECT first_name AS Name</code>.</p>



<h2 class="wp-block-heading">Verbindung herstellen und Tabellen erstellen</h2>



<p>Dapper arbeitet auf Basis von <code>IDbConnection</code>. Die Verbindung erstellst du weiterhin selbst. Verwende <code>AppContext.BaseDirectory</code> für einen zuverlässigen Pfad, wie im <a href="https://robbelroot.de/blog/vbnet-application-path/"><strong>Application Path Artikel</strong></a> beschrieben:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports Dapper
Imports Microsoft.Data.Sqlite

Dim dbPath As String = Path.Combine(AppContext.BaseDirectory, "myapp.db")
Dim connectionString As String = $"Data Source={dbPath}"

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    connection.Execute("
        CREATE TABLE IF NOT EXISTS Contacts (
            Id INTEGER PRIMARY KEY AUTOINCREMENT,
            Name TEXT NOT NULL,
            Email TEXT,
            Phone TEXT,
            CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
        )")
End Using</pre>



<p>Beachte, wie <code>connection.Execute()</code> das gesamte <code>SqliteCommand</code>&#8211; / <code>ExecuteNonQuery()</code>-Pattern ersetzt. Dapper öffnet die Verbindung automatisch, wenn sie geschlossen ist, aber ich bevorzuge es, sie explizit zu öffnen.</p>



<h2 class="wp-block-heading">Daten einfügen (INSERT)</h2>



<p>Mit rohem ADO.NET würdest du einen Command erstellen, Parameter einzeln hinzufügen und <code>ExecuteNonQuery()</code> aufrufen. Mit Dapper übergibst du ein anonymes Objekt und die Properties werden automatisch auf die Parameter gemappt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    connection.Execute(
        "INSERT INTO Contacts (Name, Email, Phone) VALUES (@Name, @Email, @Phone)",
        New With {
            .Name = "Max Mustermann",
            .Email = "max@example.com",
            .Phone = "+49 123 456789"
        })
End Using</pre>



<p>Dapper erzeugt automatisch parametrisierte Abfragen aus dem anonymen Objekt. Es besteht kein Risiko für SQL Injection, da die Werte nie in den SQL-String konkateniert werden.</p>



<h3 class="wp-block-heading">Mehrere Zeilen auf einmal einfügen</h3>



<p>Übergib eine Liste statt eines einzelnen Objekts und Dapper führt das Statement einmal pro Element aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim contacts As New List(Of Contact) From {
    New Contact With {.Name = "Alice", .Email = "alice@example.com"},
    New Contact With {.Name = "Bob", .Email = "bob@example.com"},
    New Contact With {.Name = "Clara", .Email = "clara@example.com"}
}

Using connection As New SqliteConnection(connectionString)
    connection.Open()

    connection.Execute(
        "INSERT INTO Contacts (Name, Email) VALUES (@Name, @Email)",
        contacts)
End Using</pre>



<p>Bei großen Datenmengen (Hunderte oder Tausende Zeilen) solltest du das in einer Transaktion kapseln, um die Performance deutlich zu verbessern. Dazu weiter unten mehr.</p>



<h2 class="wp-block-heading">Daten abfragen (SELECT)</h2>



<p>Hier zeigt Dapper seine wahre Stärke. Statt einen <code>DataReader</code> zu durchlaufen und jede Spalte manuell zu mappen, rufst du <code>Query(Of T)</code> auf und bekommst eine typisierte Collection zurück:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim contacts = connection.Query(Of Contact)(
        "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name")

    For Each contact In contacts
        Console.WriteLine($"[{contact.Id}] {contact.Name} - {contact.Email}")
    Next
End Using</pre>



<p>Das Ergebnis ist ein <code>IEnumerable(Of Contact)</code>, das du iterieren, mit LINQ filtern oder direkt an ein <a href="https://robbelroot.de/blog/ein-vb-net-datagridview-fuellen/"><strong>DataGridView</strong></a> binden kannst.</p>



<h3 class="wp-block-heading">Abfragen mit Parametern</h3>



<p>Parameter übergibst du wie bei <code>Execute()</code> als anonymes Objekt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim results = connection.Query(Of Contact)(
        "SELECT Id, Name, Email FROM Contacts WHERE Name LIKE @Search",
        New With {.Search = $"%{searchTerm}%"})

    For Each contact In results
        Console.WriteLine($"[{contact.Id}] {contact.Name}")
    Next
End Using</pre>



<h3 class="wp-block-heading">Einzelne Zeile abfragen</h3>



<p>Verwende <code>QueryFirstOrDefault(Of T)</code>, wenn du genau ein Ergebnis erwartest (oder keines):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim contact = connection.QueryFirstOrDefault(Of Contact)(
        "SELECT Id, Name, Email, Phone FROM Contacts WHERE Id = @Id",
        New With {.Id = 1})

    If contact IsNot Nothing Then
        Console.WriteLine($"{contact.Name} ({contact.Email})")
    End If
End Using</pre>



<p>Weitere Varianten: <code>QueryFirst</code> (Exception wenn keine Zeilen), <code>QuerySingle</code> (Exception wenn nicht genau eine Zeile), <code>QuerySingleOrDefault</code> (Exception wenn mehr als eine Zeile).</p>



<h3 class="wp-block-heading">Skalare Abfragen</h3>



<p>Für Abfragen, die einen einzelnen Wert zurückgeben, verwende <code>ExecuteScalar(Of T)</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim count = connection.ExecuteScalar(Of Long)(
        "SELECT COUNT(*) FROM Contacts")

    Console.WriteLine($"{count} Kontakte in der Datenbank")
End Using</pre>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Brauchst du eine saubere Data-Access-Schicht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Von SQLite bis SQL Server, von rohem ADO.NET bis Dapper: Ich entwerfe Datenschichten, die skalieren. Lass uns über dein Projekt sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Daten aktualisieren und löschen</h2>



<p>Updates und Deletes folgen dem gleichen Muster wie Inserts. <code>Execute()</code> gibt die Anzahl betroffener Zeilen zurück:</p>



<h3 class="wp-block-heading">UPDATE</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim rowsAffected = connection.Execute(
        "UPDATE Contacts SET Email = @Email WHERE Id = @Id",
        New With {.Email = "neue-email@example.com", .Id = 1})

    Console.WriteLine($"{rowsAffected} Zeile(n) aktualisiert.")
End Using</pre>



<h3 class="wp-block-heading">DELETE</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Dim rowsAffected = connection.Execute(
        "DELETE FROM Contacts WHERE Id = @Id",
        New With {.Id = 5})

    Console.WriteLine($"{rowsAffected} Zeile(n) gelöscht.")
End Using</pre>



<h2 class="wp-block-heading">Komplettes Beispiel: ContactRepository mit Dapper</h2>



<p>Hier ist eine vollständige Repository-Klasse für alle CRUD-Operationen. Vergleiche sie mit der <a href="https://robbelroot.de/blog/vbnet-sqlite/"><strong>manuellen ADO.NET-Version im SQLite-Artikel</strong></a>, um zu sehen, wie viel Code Dapper einspart:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports Dapper
Imports Microsoft.Data.Sqlite

Public Class ContactRepository

    Private ReadOnly _connectionString As String

    Public Sub New(connectionString As String)
        _connectionString = connectionString
    End Sub

    Public Sub InitializeDatabase()
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            connection.Execute("
                CREATE TABLE IF NOT EXISTS Contacts (
                    Id INTEGER PRIMARY KEY AUTOINCREMENT,
                    Name TEXT NOT NULL,
                    Email TEXT,
                    Phone TEXT,
                    CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
                )")
        End Using
    End Sub

    Public Function AddContact(name As String, email As String, phone As String) As Long
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            connection.Execute(
                "INSERT INTO Contacts (Name, Email, Phone) VALUES (@Name, @Email, @Phone)",
                New With {.Name = name, .Email = email, .Phone = phone})

            Return connection.ExecuteScalar(Of Long)("SELECT last_insert_rowid()")
        End Using
    End Function

    Public Function GetAllContacts() As List(Of Contact)
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Return connection.Query(Of Contact)(
                "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name").AsList()
        End Using
    End Function

    Public Function GetContactById(id As Long) As Contact
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Return connection.QueryFirstOrDefault(Of Contact)(
                "SELECT Id, Name, Email, Phone FROM Contacts WHERE Id = @Id",
                New With {.Id = id})
        End Using
    End Function

    Public Function UpdateContact(id As Long, name As String, email As String, phone As String) As Boolean
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Dim rows = connection.Execute(
                "UPDATE Contacts SET Name = @Name, Email = @Email, Phone = @Phone WHERE Id = @Id",
                New With {.Name = name, .Email = email, .Phone = phone, .Id = id})
            Return rows > 0
        End Using
    End Function

    Public Function DeleteContact(id As Long) As Boolean
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()
            Dim rows = connection.Execute(
                "DELETE FROM Contacts WHERE Id = @Id",
                New With {.Id = id})
            Return rows > 0
        End Using
    End Function
End Class</pre>



<p>Die Verwendung ist unkompliziert:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim repo As New ContactRepository($"Data Source={dbPath}")
repo.InitializeDatabase()

Dim newId = repo.AddContact("Max Mustermann", "max@example.com", "+49 123 456789")
Console.WriteLine($"Kontakt mit ID {newId} erstellt")

Dim allContacts = repo.GetAllContacts()
For Each c In allContacts
    Console.WriteLine($"[{c.Id}] {c.Name} - {c.Email}")
Next</pre>



<h2 class="wp-block-heading">Transaktionen mit Dapper</h2>



<p>Bei Bulk-Operationen solltest du eine Transaktion verwenden. Ohne Transaktion führt SQLite nach jedem einzelnen Statement einen Commit durch, was bei Hunderten von Inserts extrem langsam wird:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection(connectionString)
    connection.Open()

    Using transaction = connection.BeginTransaction()
        Dim contacts As New List(Of Object)
        For i As Integer = 1 To 1000
            contacts.Add(New With {
                .Name = $"Kontakt {i}",
                .Email = $"kontakt{i}@example.com"
            })
        Next

        connection.Execute(
            "INSERT INTO Contacts (Name, Email) VALUES (@Name, @Email)",
            contacts,
            transaction)

        transaction.Commit()
    End Using
End Using</pre>



<p>Der entscheidende Unterschied zu rohem ADO.NET: Du übergibst das <code>transaction</code>-Objekt als Parameter an <code>Execute()</code>. Kein manuelles <code>command.Transaction</code> setzen. Und weil Dapper die Liste intern durchläuft, bekommst du Transaktionssicherheit für alle 1000 Inserts mit minimalem Code.</p>



<h2 class="wp-block-heading">Async-Abfragen: GUI nicht einfrieren</h2>



<p>Jede Dapper-Methode hat ein asynchrones Pendant. Wenn du eine WinForms- oder WPF-Anwendung baust, verwende sie, damit die Oberfläche während der Datenbankaufrufe nicht einfriert. Die Grundlagen findest du im <a href="https://robbelroot.de/blog/vbnet-await/"><strong>VB.NET Async/Await Guide</strong></a>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private Async Function LoadContactsAsync() As Task(Of List(Of Contact))
    Using connection As New SqliteConnection(connectionString)
        Await connection.OpenAsync()

        Dim contacts = Await connection.QueryAsync(Of Contact)(
            "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name")

        Return contacts.AsList()
    End Using
End Function</pre>



<p>Verfügbare Async-Methoden: <code>QueryAsync</code>, <code>QueryFirstOrDefaultAsync</code>, <code>ExecuteAsync</code>, <code>ExecuteScalarAsync</code>. Sie funktionieren genau wie ihre synchronen Gegenstücke, nur mit <code>Await</code>.</p>



<h2 class="wp-block-heading">Dapper vs. ADO.NET: Direktvergleich</h2>



<p>Hier die gleiche &#8222;alle Kontakte laden&#8220;-Operation auf beide Arten. Zuerst reines ADO.NET, wie im <a href="https://robbelroot.de/blog/vbnet-sqlite/"><strong>SQLite-Artikel</strong></a> gezeigt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Reines ADO.NET - 13 Zeilen
Using connection As New SqliteConnection(connectionString)
    connection.Open()
    Using command As New SqliteCommand("SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name", connection)
        Using reader = command.ExecuteReader()
            While reader.Read()
                Dim contact As New Contact With {
                    .Id = reader.GetInt64(0),
                    .Name = reader.GetString(1),
                    .Email = If(reader.IsDBNull(2), "", reader.GetString(2)),
                    .Phone = If(reader.IsDBNull(3), "", reader.GetString(3))
                }
                contacts.Add(contact)
            End While
        End Using
    End Using
End Using</pre>



<p>Und jetzt das gleiche mit Dapper:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' Dapper - 4 Zeilen
Using connection As New SqliteConnection(connectionString)
    connection.Open()
    Dim contacts = connection.Query(Of Contact)(
        "SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name").AsList()
End Using</pre>



<p>Gleiches Ergebnis, gleiches SQL, gleiche Performance. Dapper übernimmt die Reader-Schleife, die Null-Checks und das Property-Mapping automatisch. Je komplexer das Datenmodell, desto größer der Unterschied.</p>



<h2 class="wp-block-heading">Häufige Stolperfallen und Tipps</h2>



<h3 class="wp-block-heading">Property-Namen müssen zu Spaltennamen passen</h3>



<p>Dapper mappt nach Name, Groß-/Kleinschreibung wird ignoriert. Wenn deine Tabelle <code>first_name</code> hat, dein Property aber <code>FirstName</code> heißt, verwende einen SQL-Alias:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim contacts = connection.Query(Of Contact)(
    "SELECT first_name AS FirstName, last_name AS LastName FROM Contacts")</pre>



<h3 class="wp-block-heading">NULL-Werte</h3>



<p>Dapper behandelt <code>NULL</code>-Spalten automatisch. Wenn eine Spalte <code>NULL</code> ist und das Ziel-Property ein <code>String</code>, wird es zu <code>Nothing</code>. Wenn du stattdessen einen leeren String willst, initialisiere deine Properties mit Standardwerten:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Class Contact
    Public Property Id As Long
    Public Property Name As String = ""
    Public Property Email As String = ""
    Public Property Phone As String = ""
End Class</pre>



<h3 class="wp-block-heading">Using-Blöcke nicht vergessen</h3>



<p>Dapper verwaltet keine Verbindungs-Lebenszeiten. Du brauchst weiterhin <code>Using</code>-Blöcke für jede Verbindung, genau wie bei rohem ADO.NET. Eine offene Verbindung sperrt die SQLite-Datei.</p>



<h3 class="wp-block-heading">Dapper und Dependency Injection</h3>



<p>In größeren Anwendungen solltest du den Connection String per Injection übergeben statt ihn hardzucoden. Die <code>ContactRepository</code>-Klasse oben folgt bereits diesem Muster. Wenn du einen DI-Container wie Autofac einsetzt, schau dir den <a href="https://robbelroot.de/blog/net-dependency-injection-di-mit-autofac/"><strong>Dependency Injection Guide</strong></a> an.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Erfahrenen .NET-Entwickler gesucht?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme dein Projekt, vom Datenbankdesign bis zur fertigen Anwendung. Schreib mir einfach eine Nachricht.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-dapper-de-1"><strong class="schema-faq-question"><strong>Was ist Dapper in VB.NET?</strong></strong> <p class="schema-faq-answer">Dapper ist ein leichtgewichtiger Micro ORM, der <code>IDbConnection</code> um Methoden wie <code>Query(Of T)</code> und <code>Execute()</code> erweitert. Er mappt SQL-Ergebnisse direkt auf VB.NET-Klassen, ohne den Overhead eines vollen ORM wie Entity Framework.</p> </div> <div class="schema-faq-section" id="faq-dapper-de-2"><strong class="schema-faq-question"><strong>Ist Dapper schneller als Entity Framework?</strong></strong> <p class="schema-faq-answer">Ja. Dapper ist fast so schnell wie reines ADO.NET, weil es minimalen Overhead erzeugt. Entity Framework fügt Change Tracking, Proxy-Generierung und Query-Translation hinzu, was es bei einfachen Operationen langsamer macht.</p> </div> <div class="schema-faq-section" id="faq-dapper-de-3"><strong class="schema-faq-question"><strong>Kann ich Dapper mit SQLite in VB.NET verwenden?</strong></strong> <p class="schema-faq-answer">Ja. Installiere <code>Dapper</code> und <code>Microsoft.Data.Sqlite</code> per NuGet. Dapper arbeitet mit jeder <code>IDbConnection</code>, also funktioniert <code>SqliteConnection</code> ohne weitere Konfiguration.</p> </div> <div class="schema-faq-section" id="faq-dapper-de-4"><strong class="schema-faq-question"><strong>Wie gehe ich mit NULL-Werten bei Dapper um?</strong></strong> <p class="schema-faq-answer">Dapper mappt <code>NULL</code>-Spalten auf <code>Nothing</code> bei Referenztypen. Wenn du leere Strings bevorzugst, initialisiere deine Properties mit Standardwerten wie <code>Public Property Email As String = ""</code>.</p> </div> <div class="schema-faq-section" id="faq-dapper-de-5"><strong class="schema-faq-question"><strong>Unterstützt Dapper Async/Await?</strong></strong> <p class="schema-faq-answer">Ja. Jede Dapper-Methode hat ein asynchrones Gegenstück: <code>QueryAsync</code>, <code>ExecuteAsync</code>, <code>ExecuteScalarAsync</code> usw. Verwende sie mit <code>Await</code> in WinForms- oder WPF-Anwendungen, um die Oberfläche reaktionsfähig zu halten.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>Dapper eliminiert das repetitive ADO.NET-Boilerplate, während du die volle Kontrolle über dein SQL behältst. Installiere das NuGet-Paket, definiere eine Model-Klasse und ersetze dein manuelles <code>SqliteCommand</code>&#8211; / <code>DataReader</code>-Code durch <code>Query(Of T)</code> und <code>Execute()</code>. Wenn du deine Datenbank noch nicht aufgesetzt hast, starte zuerst mit dem <a href="https://robbelroot.de/blog/vbnet-sqlite/"><strong>VB.NET SQLite Guide</strong></a> und komm dann hierher zurück, um deine Datenzugriffsschicht zu vereinfachen.</p>


<!--
=== YOAST SEO SETTINGS ===
Focus Keyword: VB.NET Dapper
SEO Title: VB.NET Dapper – Micro ORM für sauberen Datenzugriff (2026)
Slug: vbnet-dapper
Meta Description: Dapper in VB.NET nutzen: per NuGet installieren, SQL-Ergebnisse auf Klassen mappen, CRUD parametrisiert ausführen. Mit SQLite-Beispiel.
=== END YOAST SEO SETTINGS ===
--><p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-dapper/">VB.NET Dapper – Micro ORM für sauberen Datenzugriff (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-dapper/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET SQLite Datenbank – Verbinden, Lesen, Schreiben (2026)</title>
		<link>https://robbelroot.de/blog/vbnet-sqlite/</link>
					<comments>https://robbelroot.de/blog/vbnet-sqlite/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 20:42:24 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20407</guid>

					<description><![CDATA[<p>SQLite ist der einfachste Weg, eine lokale Datenbank in Deine VB.NET-Anwendung einzubauen, kein Server, keine Installation, keine Konfiguration. In diesem Guide zeige ich Dir Schritt für Schritt, wie Du SQLite per NuGet einrichtest, Tabellen anlegst und alle CRUD-Operationen mit parametrisierten Abfragen durchführst. Mit komplettem Praxisbeispiel zum Download. → Direkt zum &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-sqlite/">VB.NET SQLite Datenbank – Verbinden, Lesen, Schreiben (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><strong>SQLite</strong> ist der einfachste Weg, eine lokale Datenbank in Deine <strong>VB.NET</strong>-Anwendung einzubauen, kein Server, keine Installation, keine Konfiguration. In diesem Guide zeige ich Dir Schritt für Schritt, wie Du SQLite per NuGet einrichtest, Tabellen anlegst und alle CRUD-Operationen mit parametrisierten Abfragen durchführst. Mit komplettem Praxisbeispiel zum Download. → <a href="#downloads"><strong>Direkt zum Download</strong></a>.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Datenbank-Hilfe gesucht?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du brauchst Unterstützung bei der Datenbank-Integration?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Seit über 17 Jahren entwickle ich professionell in VB.NET und C#. Ob SQLite, SQL Server oder Datenarchitektur – ich helfe Dir weiter.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Warum SQLite für Deine VB.NET-Anwendung?</h2>



<p>Es gibt viele Datenbank-Engines, aber SQLite sticht bei lokalen VB.NET-Anwendungen besonders hervor. Die Gründe:</p>



<ul class="wp-block-list">
<li><strong>Kein Setup</strong> – kein Serverprozess, keine Installation, keine Admin-Rechte nötig</li>



<li><strong>Eine einzige Datei</strong> – die gesamte Datenbank lebt in einer <code>.db</code>-Datei, die Du mit Deiner App ausliefern kannst</li>



<li><strong>Plattformübergreifend</strong> – läuft auf Windows, Linux und macOS</li>



<li><strong>Leichtgewichtig</strong> – perfekt für Desktop-Apps, Prototypen, Embedded-Systeme und Offline-First-Szenarien</li>



<li><strong>Zuverlässig</strong> – wird von Firefox, Chrome, Android und Millionen anderer Anwendungen eingesetzt</li>
</ul>



<p>Wenn Du nur Einstellungen oder kleine Datenmengen speichern möchtest, reicht es oft auch, eine <a href="https://robbelroot.de/blog/vbnet-textdatei-schreiben/"><strong>Textdatei in VB.NET zu schreiben</strong></a>. Sobald Du aber strukturierte Daten, Abfragen oder Beziehungen brauchst, ist SQLite die bessere Wahl.</p>



<h2 class="wp-block-heading">Das NuGet-Paket installieren</h2>



<p>Es gibt zwei populäre SQLite-Pakete für .NET:</p>



<ol class="wp-block-list">
<li><code>Microsoft.Data.Sqlite</code> – Microsofts offizielles, leichtgewichtiges Paket (empfohlen für .NET 5+ / .NET Framework 4.6.1+)</li>



<li><code>System.Data.SQLite</code> – das ältere, umfangreichere Paket vom SQLite-Team (unterstützt auch .NET Framework 4.0)</li>
</ol>



<p>In diesem Artikel verwende ich <code>Microsoft.Data.Sqlite</code>, da es schlanker ist und der empfohlene Weg für die Zukunft. Die API ist nahezu identisch, ein späterer Wechsel ist also unkompliziert.</p>



<h3 class="wp-block-heading">Installation per Package Manager Console</h3>



<p>Öffne die Package Manager Console in Visual Studio (<em>Tools → NuGet Package Manager → Package Manager Console</em>) und führe aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Install-Package Microsoft.Data.Sqlite</pre>



<p>Alternativ: Rechtsklick auf das Projekt im Solution Explorer → <em>NuGet-Pakete verwalten</em> → nach <code>Microsoft.Data.Sqlite</code> suchen → Installieren.</p>



<h3 class="wp-block-heading">Die Imports-Anweisung ergänzen</h3>



<p>Am Anfang Deiner Code-Datei fügst Du folgenden Import hinzu:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports Microsoft.Data.Sqlite</pre>



<h2 class="wp-block-heading">Datenbank erstellen und verbinden</h2>



<p>Ein großer Vorteil von SQLite: Du musst keine Datenbank manuell anlegen. Wenn die Datei noch nicht existiert, erstellt SQLite sie automatisch beim Öffnen der Verbindung.</p>



<h3 class="wp-block-heading">Der Connection String</h3>



<p>Der SQLite Connection String ist minimal. Du brauchst nur den Pfad zur Datenbankdatei:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim connectionString As String = "Data Source=myapp.db"</pre>



<p>Damit wird die Datei <code>myapp.db</code> im Arbeitsverzeichnis der Anwendung erstellt. Wenn Du die Datenbank neben der EXE-Datei ablegen möchtest, kannst Du den <a href="https://robbelroot.de/blog/vbnet-application-path/"><strong>VB.NET Application Path</strong></a> verwenden, um einen zuverlässigen Pfad zu bauen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim dbPath As String = Path.Combine(AppContext.BaseDirectory, "myapp.db")
Dim connectionString As String = $"Data Source={dbPath}"</pre>



<h3 class="wp-block-heading">Verbindung öffnen</h3>



<p>Packe Deine Verbindung immer in einen <code>Using</code>-Block. So wird die Verbindung auch bei einer Exception sauber geschlossen und freigegeben:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    ' Deine Datenbankoperationen hier...

End Using ' Verbindung wird automatisch geschlossen</pre>



<p>Das ist das Grundmuster für jede Datenbankoperation. Der <code>Using</code>-Block ist essenziell, um File-Locks und „database is locked&#8220;-Fehler zu vermeiden (dazu später mehr).</p>



<h2 class="wp-block-heading">Tabellen anlegen</h2>



<p>Bevor Du Daten speichern kannst, brauchst Du mindestens eine Tabelle. Verwende <code>CREATE TABLE IF NOT EXISTS</code>, damit der Befehl bei jedem App-Start sicher ausgeführt werden kann, ohne Fehler, falls die Tabelle schon existiert:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand()
        command.Connection = connection
        command.CommandText = "
            CREATE TABLE IF NOT EXISTS Contacts (
                Id INTEGER PRIMARY KEY AUTOINCREMENT,
                Name TEXT NOT NULL,
                Email TEXT,
                Phone TEXT,
                CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
            )"
        command.ExecuteNonQuery()
    End Using
End Using</pre>



<h3 class="wp-block-heading">SQLite-Datentypen</h3>



<p>SQLite verwendet ein dynamisches Typsystem, das sich von SQL Server unterscheidet. Die gängigsten Typen sind:</p>



<ul class="wp-block-list">
<li><code>INTEGER</code> – Ganzzahlen (entspricht Integer / Long in VB.NET)</li>



<li><code>TEXT</code> – Zeichenketten (entspricht String)</li>



<li><code>REAL</code> – Gleitkommazahlen (entspricht Double)</li>



<li><code>BLOB</code> – Binärdaten (entspricht Byte())</li>



<li><code>NULL</code> – kein Wert</li>
</ul>



<p>Ein Tipp: SQLite hat keinen nativen <code>DATETIME</code>-Typ. Speichere Datumsangaben als <code>TEXT</code> im ISO-8601-Format (z. B. <code>2026-04-07T14:30:00</code>) oder als <code>INTEGER</code> (Unix-Timestamp).</p>



<h2 class="wp-block-heading">Daten einfügen (INSERT)</h2>



<p>Jetzt fügen wir einen Datensatz in unsere Contacts-Tabelle ein. <strong>Verwende immer parametrisierte Abfragen</strong> statt String-Verkettung. Das schützt Deine App vor SQL Injection und behandelt Sonderzeichen korrekt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand()
        command.Connection = connection
        command.CommandText = "INSERT INTO Contacts (Name, Email, Phone) VALUES (@name, @email, @phone)"
        command.Parameters.AddWithValue("@name", "Max Mustermann")
        command.Parameters.AddWithValue("@email", "max@example.com")
        command.Parameters.AddWithValue("@phone", "+49 123 456789")
        command.ExecuteNonQuery()
    End Using
End Using</pre>



<h3 class="wp-block-heading">Warum parametrisierte Abfragen wichtig sind</h3>



<p>Baue SQL-Strings niemals durch direktes Zusammensetzen von Benutzereingaben zusammen. Das ist der häufigste Sicherheitsfehler, der zu SQL Injection führt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">' &#x274c; NIEMALS so machen - SQL-Injection-Schwachstelle!
command.CommandText = "INSERT INTO Contacts (Name) VALUES ('" &amp; txtName.Text &amp; "')"

' &#x2705; Immer Parameter verwenden
command.CommandText = "INSERT INTO Contacts (Name) VALUES (@name)"
command.Parameters.AddWithValue("@name", txtName.Text)</pre>



<h3 class="wp-block-heading">Die zuletzt eingefügte ID abfragen</h3>



<p>Nach dem Einfügen einer Zeile möchtest Du häufig die automatisch generierte ID wissen. Dafür gibt es <code>last_insert_rowid()</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">command.CommandText = "INSERT INTO Contacts (Name, Email) VALUES (@name, @email)"
command.Parameters.AddWithValue("@name", "Erika Musterfrau")
command.Parameters.AddWithValue("@email", "erika@example.com")
command.ExecuteNonQuery()

command.CommandText = "SELECT last_insert_rowid()"
Dim newId As Long = CLng(command.ExecuteScalar())
Console.WriteLine($"Neuer Kontakt-ID: {newId}")</pre>



<h2 class="wp-block-heading">Daten lesen (SELECT)</h2>



<p>Verwende <code>ExecuteReader()</code>, um Daten abzufragen und über die Ergebnisse zu iterieren. Auch hier: alles in <code>Using</code>-Blöcke verpacken:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand("SELECT Id, Name, Email FROM Contacts", connection)
        Using reader As SqliteDataReader = command.ExecuteReader()
            While reader.Read()
                Dim id As Long = reader.GetInt64(0)
                Dim name As String = reader.GetString(1)
                Dim email As String = If(reader.IsDBNull(2), "", reader.GetString(2))

                Console.WriteLine($"[{id}] {name} - {email}")
            End While
        End Using
    End Using
End Using</pre>



<h3 class="wp-block-heading">Filtern mit WHERE</h3>



<p>Um nach bestimmten Datensätzen zu suchen, verwende eine parametrisierte <code>WHERE</code>-Klausel:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using command As New SqliteCommand(
    "SELECT Id, Name, Email FROM Contacts WHERE Name LIKE @search",
    connection)
    command.Parameters.AddWithValue("@search", $"%{searchTerm}%")

    Using reader As SqliteDataReader = command.ExecuteReader()
        While reader.Read()
            ' Ergebnisse verarbeiten...
        End While
    End Using
End Using</pre>



<p>Die Ergebnisse lassen sich anschließend beispielsweise in einem <a href="https://robbelroot.de/blog/ein-vb-net-datagridview-fuellen/"><strong>VB.NET DataGridView</strong></a> anzeigen. Zum Speichern der Ergebnisse nach Schlüssel ist das <a href="https://robbelroot.de/blog/vb-net-dictionary-ein-kompletter-guide/"><strong>VB.NET Dictionary</strong></a> eine passende Datenstruktur.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Projekt in Planung?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du brauchst eine .NET Desktop-Anwendung mit Datenbank?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Vom Datenmodell bis zur fertigen WinForms- oder WPF-App setze ich Dein Projekt um. Lass uns über Deine Anforderungen sprechen.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">Daten aktualisieren und löschen</h2>



<h3 class="wp-block-heading">UPDATE</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand()
        command.Connection = connection
        command.CommandText = "UPDATE Contacts SET Email = @email WHERE Id = @id"
        command.Parameters.AddWithValue("@email", "neue-email@example.com")
        command.Parameters.AddWithValue("@id", 1)

        Dim rowsAffected As Integer = command.ExecuteNonQuery()
        Console.WriteLine($"{rowsAffected} Zeile(n) aktualisiert.")
    End Using
End Using</pre>



<h3 class="wp-block-heading">DELETE</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using command As New SqliteCommand("DELETE FROM Contacts WHERE Id = @id", connection)
        command.Parameters.AddWithValue("@id", 5)

        Dim rowsAffected As Integer = command.ExecuteNonQuery()
        Console.WriteLine($"{rowsAffected} Zeile(n) gelöscht.")
    End Using
End Using</pre>



<h2 class="wp-block-heading">Komplettes Beispiel: Kontaktverwaltung</h2>



<p>Jetzt bringen wir alles zusammen. Hier ist eine komplette Helper-Klasse, die alle CRUD-Operationen für eine Contacts-Tabelle kapselt. Du kannst sie als Ausgangspunkt für Deine eigenen Projekte verwenden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports Microsoft.Data.Sqlite

Public Class ContactRepository

    Private ReadOnly _connectionString As String

    Public Sub New(dbPath As String)
        _connectionString = $"Data Source={dbPath}"
    End Sub

    ''' Stellt sicher, dass die Contacts-Tabelle existiert.
    Public Sub InitializeDatabase()
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand()
                command.Connection = connection
                command.CommandText = "
                    CREATE TABLE IF NOT EXISTS Contacts (
                        Id INTEGER PRIMARY KEY AUTOINCREMENT,
                        Name TEXT NOT NULL,
                        Email TEXT,
                        Phone TEXT,
                        CreatedAt TEXT DEFAULT CURRENT_TIMESTAMP
                    )"
                command.ExecuteNonQuery()
            End Using
        End Using
    End Sub

    ''' Fügt einen neuen Kontakt hinzu und gibt die generierte Id zurück.
    Public Function AddContact(name As String, email As String, phone As String) As Long
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand()
                command.Connection = connection
                command.CommandText = "
                    INSERT INTO Contacts (Name, Email, Phone)
                    VALUES (@name, @email, @phone)"
                command.Parameters.AddWithValue("@name", name)
                command.Parameters.AddWithValue("@email", CObj(email) ?? DBNull.Value)
                command.Parameters.AddWithValue("@phone", CObj(phone) ?? DBNull.Value)
                command.ExecuteNonQuery()
            End Using

            Using command As New SqliteCommand("SELECT last_insert_rowid()", connection)
                Return CLng(command.ExecuteScalar())
            End Using
        End Using
    End Function

    ''' Gibt alle Kontakte als Liste von Dictionaries zurück.
    Public Function GetAllContacts() As List(Of Dictionary(Of String, Object))
        Dim contacts As New List(Of Dictionary(Of String, Object))

        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand("SELECT Id, Name, Email, Phone FROM Contacts ORDER BY Name", connection)
                Using reader As SqliteDataReader = command.ExecuteReader()
                    While reader.Read()
                        Dim contact As New Dictionary(Of String, Object) From {
                            {"Id", reader.GetInt64(0)},
                            {"Name", reader.GetString(1)},
                            {"Email", If(reader.IsDBNull(2), "", reader.GetString(2))},
                            {"Phone", If(reader.IsDBNull(3), "", reader.GetString(3))}
                        }
                        contacts.Add(contact)
                    End While
                End Using
            End Using
        End Using

        Return contacts
    End Function

    ''' Aktualisiert einen Kontakt anhand der Id.
    Public Function UpdateContact(id As Long, name As String, email As String, phone As String) As Boolean
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand()
                command.Connection = connection
                command.CommandText = "UPDATE Contacts SET Name = @name, Email = @email, Phone = @phone WHERE Id = @id"
                command.Parameters.AddWithValue("@name", name)
                command.Parameters.AddWithValue("@email", CObj(email) ?? DBNull.Value)
                command.Parameters.AddWithValue("@phone", CObj(phone) ?? DBNull.Value)
                command.Parameters.AddWithValue("@id", id)

                Return command.ExecuteNonQuery() > 0
            End Using
        End Using
    End Function

    ''' Löscht einen Kontakt anhand der Id.
    Public Function DeleteContact(id As Long) As Boolean
        Using connection As New SqliteConnection(_connectionString)
            connection.Open()

            Using command As New SqliteCommand("DELETE FROM Contacts WHERE Id = @id", connection)
                command.Parameters.AddWithValue("@id", id)

                Return command.ExecuteNonQuery() > 0
            End Using
        End Using
    End Function

End Class</pre>



<h3 class="wp-block-heading">Das ContactRepository verwenden</h3>



<p>So verwendest Du die Klasse, zum Beispiel im Form_Load-Event einer WinForms-Anwendung:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim dbPath As String = Path.Combine(AppContext.BaseDirectory, "contacts.db")
Dim repo As New ContactRepository(dbPath)

' Tabelle anlegen (kann bei jedem Start aufgerufen werden)
repo.InitializeDatabase()

' Kontakt hinzufügen
Dim newId As Long = repo.AddContact("Robert Skibbe", "mail@robbelroot.de", "+49 123 456")
Console.WriteLine($"Kontakt mit ID {newId} angelegt")

' Alle Kontakte auslesen
For Each contact In repo.GetAllContacts()
    Console.WriteLine($"[{contact("Id")}] {contact("Name")} - {contact("Email")}")
Next

' Kontakt aktualisieren
repo.UpdateContact(newId, "Robert S.", "neu@robbelroot.de", "+49 999 999")

' Kontakt löschen
repo.DeleteContact(newId)</pre>



<h2 class="wp-block-heading">Transaktionen verwenden</h2>



<p>Wenn Du mehrere Zeilen auf einmal einfügen oder aktualisieren musst, packe sie in eine Transaktion. Das ist sowohl schneller als auch sicherer: entweder gelingen alle Operationen oder keine.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using transaction = connection.BeginTransaction()
        Using command As New SqliteCommand()
            command.Connection = connection
            command.Transaction = transaction
            command.CommandText = "INSERT INTO Contacts (Name, Email) VALUES (@name, @email)"

            For i As Integer = 1 To 1000
                command.Parameters.Clear()
                command.Parameters.AddWithValue("@name", $"Kontakt {i}")
                command.Parameters.AddWithValue("@email", $"kontakt{i}@example.com")
                command.ExecuteNonQuery()
            Next
        End Using

        transaction.Commit()
    End Using
End Using</pre>



<p>Ohne Transaktion kann das Einfügen von 1.000 Zeilen mehrere Sekunden dauern, da SQLite nach jedem einzelnen INSERT committet. Mit Transaktion ist die gleiche Operation in Millisekunden erledigt.</p>



<h2 class="wp-block-heading">Async/Await: GUI nicht einfrieren</h2>



<p>Läuft eine Datenbankabfrage auf dem UI-Thread, friert die gesamte Benutzeroberfläche so lange ein. Mit Async/Await verlagerst Du die Arbeit in den Hintergrund, während die GUI weiter reagiert. Alles zum Thema findest Du im Beitrag zur <a href="https://robbelroot.de/blog/vbnet-await/"><strong>asynchronen Programmierung in VB.NET</strong></a>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Async Function GetAllContactsAsync() As Task(Of List(Of Dictionary(Of String, Object)))
    Dim contacts As New List(Of Dictionary(Of String, Object))

    Using connection As New SqliteConnection(_connectionString)
        Await connection.OpenAsync()

        Using command As New SqliteCommand("SELECT Id, Name, Email FROM Contacts ORDER BY Name", connection)
            Using reader As SqliteDataReader = Await command.ExecuteReaderAsync()
                While Await reader.ReadAsync()
                    Dim contact As New Dictionary(Of String, Object) From {
                        {"Id", reader.GetInt64(0)},
                        {"Name", reader.GetString(1)},
                        {"Email", If(reader.IsDBNull(2), "", reader.GetString(2))}
                    }
                    contacts.Add(contact)
                End While
            End Using
        End Using
    End Using

    Return contacts
End Function</pre>



<p>Das Muster gilt für alle Operationen: <code>OpenAsync()</code> statt <code>Open()</code>, <code>ExecuteNonQueryAsync()</code> statt <code>ExecuteNonQuery()</code>, <code>ReadAsync()</code> statt <code>Read()</code>. Die aufrufende Methode muss dafür als <code>Async Function</code> deklariert sein.</p>



<h2 class="wp-block-heading">Häufige Stolperfallen und Lösungen</h2>



<h3 class="wp-block-heading">„Database is locked&#8220;</h3>



<p>Das ist der häufigste SQLite-Fehler. Er tritt auf, wenn mehrere Threads oder Verbindungen gleichzeitig in die Datenbank schreiben wollen. So vermeidest Du ihn:</p>



<ul class="wp-block-list">
<li><strong>Verbindungen immer freigeben</strong> – verwende <code>Using</code>-Blöcke konsequent. Eine vergessene offene Verbindung sperrt die Datei.</li>



<li><strong>WAL-Modus aktivieren</strong> – Write-Ahead Logging erlaubt gleichzeitiges Lesen und einen schreibenden Zugriff:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using connection As New SqliteConnection("Data Source=myapp.db")
    connection.Open()

    Using walCommand As New SqliteCommand("PRAGMA journal_mode=WAL;", connection)
        walCommand.ExecuteNonQuery()
    End Using
End Using</pre>



<ul class="wp-block-list">
<li><strong>Busy-Timeout setzen</strong> – statt sofort zu scheitern, lässt Du SQLite ein paar Sekunden lang erneut versuchen:</li>
</ul>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Using walCommand As New SqliteCommand("PRAGMA busy_timeout=5000;", connection)
    walCommand.ExecuteNonQuery()
End Using</pre>



<ul class="wp-block-list">
<li><strong>Transaktionen nutzen</strong> bei Bulk-Operationen, statt Verbindungen in einer engen Schleife zu öffnen und zu schließen.</li>



<li><strong>Lange Lesezugriffe vermeiden</strong> während geschrieben wird. Für komplexere Hintergrundarbeit bietet sich <a href="https://robbelroot.de/blog/vbnet-await/"><strong>asynchrone Programmierung in VB.NET</strong></a> an.</li>
</ul>



<h3 class="wp-block-heading">Dateipfad-Probleme</h3>



<p>Ein relativer Pfad wie <code>Data Source=myapp.db</code> wird relativ zum aktuellen Arbeitsverzeichnis aufgelöst, das sich je nach Startart unterscheiden kann (Doppelklick vs. Kommandozeile). Verwende einen absoluten Pfad auf Basis von <code>AppContext.BaseDirectory</code>, wie im <a href="https://robbelroot.de/blog/vbnet-application-path/"><strong>Application-Path-Artikel</strong></a> gezeigt.</p>



<h3 class="wp-block-heading">NULL-Behandlung</h3>



<p>Prüfe beim Lesen von nullable Spalten immer mit <code>reader.IsDBNull()</code>, bevor Du <code>GetString()</code> oder <code>GetInt64()</code> aufrufst. Sonst bekommst Du zur Laufzeit eine <code>InvalidCastException</code>. Beim Einfügen von NULL-Werten übergibst Du <code>DBNull.Value</code> statt <code>Nothing</code>.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Interessiert?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">Du suchst einen erfahrenen .NET-Entwickler?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich übernehme Dein Projekt, vom Datenbank-Design bis zur fertigen Anwendung. Schreib mir einfach.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-sqlite-de-1"><strong class="schema-faq-question"><strong>Wie erstelle ich eine SQLite-Datenbank in VB.NET?</strong></strong> <p class="schema-faq-answer">Öffne einfach eine Verbindung mit einem Dateipfad, der noch nicht existiert: <code>New SqliteConnection("Data Source=myapp.db")</code>. SQLite erstellt die Datei automatisch beim Aufruf von <code>Open()</code>.</p> </div> <div class="schema-faq-section" id="faq-sqlite-de-2"><strong class="schema-faq-question"><strong>Wie lautet der SQLite Connection String für VB.NET?</strong></strong> <p class="schema-faq-answer">Der minimale Connection String ist <code>Data Source=pfad\zur\datenbank.db</code>. Je nach Bedarf kannst Du Optionen wie <code>Mode=ReadWrite</code> oder <code>Cache=Shared</code> ergänzen.</p> </div> <div class="schema-faq-section" id="faq-sqlite-de-3"><strong class="schema-faq-question"><strong>Warum bekomme ich &#8222;database is locked&#8220; in SQLite?</strong></strong> <p class="schema-faq-answer">Das passiert, wenn mehrere Verbindungen gleichzeitig schreibend zugreifen oder eine Verbindung nicht sauber geschlossen wurde. Verwende <code>Using</code>-Blöcke, aktiviere den WAL-Modus mit <code>PRAGMA journal_mode=WAL</code> und setze einen Busy-Timeout.</p> </div> <div class="schema-faq-section" id="faq-sqlite-de-4"><strong class="schema-faq-question"><strong>Microsoft.Data.Sqlite oder System.Data.SQLite?</strong></strong> <p class="schema-faq-answer"><code>Microsoft.Data.Sqlite</code> ist schlanker, modern und wird von Microsoft gepflegt. <code>System.Data.SQLite</code> ist älter und unterstützt auch .NET Framework 4.0+. Für neue Projekte ab .NET 5+ oder .NET Framework 4.6.1+ ist <code>Microsoft.Data.Sqlite</code> die empfohlene Wahl.</p> </div> <div class="schema-faq-section" id="faq-sqlite-de-5"><strong class="schema-faq-question"><strong>Kann ich SQLite mit Async/Await in VB.NET verwenden?</strong></strong> <p class="schema-faq-answer">Ja. <code>Microsoft.Data.Sqlite</code> bietet asynchrone Methoden wie <code>ExecuteNonQueryAsync()</code>, <code>ExecuteReaderAsync()</code> und <code>ExecuteScalarAsync()</code>. Nutze sie mit <code>Await</code>, um die Benutzeroberfläche während der Datenbankoperationen nicht einfrieren zu lassen.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<p>SQLite ist der schnellste Weg, eine lokale Datenbank in Deine VB.NET-Anwendung einzubauen. Installiere <code>Microsoft.Data.Sqlite</code> per NuGet, verwende <code>Using</code>-Blöcke für jede Verbindung und schreibe ausschließlich parametrisierte Abfragen. Für Multi-Thread-Szenarien aktiviere den WAL-Modus und setze einen Busy-Timeout, um „database is locked&#8220;-Fehler zu vermeiden.</p>



<h2 class="wp-block-heading" id="downloads">Downloads</h2>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/downloads/vbnet/VbNetSqliteExample.zip" target="_blank" rel="noreferrer noopener"><strong>VbNetSqliteExample.zip</strong></a></div>
</div>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2026/04/vbnet-sqlite-winforms-beispiel.png"><img fetchpriority="high" decoding="async" width="536" height="484" src="https://robbelroot.de/wp-content/uploads/2026/04/vbnet-sqlite-winforms-beispiel.png" alt="VB.NET SQLite Beispielprojekt – WinForms App mit DataGridView und CRUD-Buttons" class="wp-image-20429"/></a></figure>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-sqlite/">VB.NET SQLite Datenbank – Verbinden, Lesen, Schreiben (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-sqlite/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>C# String Format – Interpolation, Zahlen, Datum (2026)</title>
		<link>https://robbelroot.de/blog/csharp-string-format/</link>
					<comments>https://robbelroot.de/blog/csharp-string-format/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 17:01:18 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[C# (C Sharp)]]></category>
		<category><![CDATA[C# Problemlösungen]]></category>
		<category><![CDATA[Tutorials]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=20374</guid>

					<description><![CDATA[<p>Mit C# String Format machst du aus Rohwerten lesbare, lokalisierte Ausgaben. Dieser Beitrag zeigt drei Wege: Verkettung, String.Format und String-Interpolation. Du lernst außerdem, wie du Zahlen, Währungen, DateTimes und eigene Objekte mit CultureInfo formatierst. Wie formatiert man einen String in C#? Es gibt viele Situationen, in denen du sauber formatierte &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/csharp-string-format/">C# String Format – Interpolation, Zahlen, Datum (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Mit C# String Format machst du aus Rohwerten lesbare, lokalisierte Ausgaben. Dieser Beitrag zeigt drei Wege: Verkettung, String.Format und String-Interpolation. Du lernst außerdem, wie du Zahlen, Währungen, DateTimes und eigene Objekte mit CultureInfo formatierst.</p>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Auftrag?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">C#-Entwicklung für dein Projekt?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich arbeite täglich mit C# und .NET. Ob Formatierungslogik, Architektur oder komplette Anwendungen – schreib mir einfach.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	





<h2 class="wp-block-heading">Wie formatiert man einen String in C#?</h2>



<p>Es gibt viele Situationen, in denen du sauber formatierte Strings brauchst. Stell dir eine Rechnung vor, bei der der Betrag einfach &#8222;14&#8220; lautet. Zunächst könnte man fragen: &#8222;Vierzehn wovon?&#8220; Und in der Regel möchte man zwei Dezimalstellen sehen. Aber auch das Anzeigen einer Personenliste in einer <a href="https://robbelroot.de/blog/the-wpf-listview-control-the-complete-guide/">WPF ListView</a> berührt das Thema String-Formatierung.</p>



<h3 class="wp-block-heading">Die verschiedenen Ansätze zur String-Formatierung</h3>



<p>Wenn es um das Formatieren von Strings in C# geht, gibt es 3 Hauptansätze:</p>



<ul class="wp-block-list">
<li>Strings manuell verketten</li>



<li>eine Funktion der String-Klasse verwenden</li>



<li>die neuere String-Interpolation nutzen</li>
</ul>



<p>Verkettung (Concatenation) bedeutet, mehrere Strings zu einem zusammenzufügen. Das einfachste Beispiel dafür folgt im nächsten Abschnitt: zwei Namensteile zu einem vollständigen Namen zusammensetzen.</p>



<h2 class="wp-block-heading">Einen String durch manuelle Verkettung formatieren</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/08/csharp-String-Format-using-concatenation.png"><img decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/08/csharp-String-Format-using-concatenation.png" alt="C# String Format per Verkettung" class="wp-image-11668" title="C# String Format per Verkettung"/></a><figcaption class="wp-element-caption">C# String Format per Verkettung</figcaption></figure>



<p>Schauen wir uns die erste Methode zur String-Formatierung an: die einfache Verkettung. Wie bereits erklärt, entsteht dabei ein komplett neuer String aus mehreren Einzelteilen. Du bist dabei nicht auf eine bestimmte Anzahl von Strings beschränkt.</p>



<p>Betrachten wir nun das erste kleine Beispiel: einen vollständigen Namen aus Namensteilen zusammensetzen. Dazu erstellen wir im ersten Schritt zwei Variablen und kombinieren sie dann.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">string firstName = "John";
string lastName = "Doe";</pre>



<p>Nach dem Erstellen der Variablen können wir sie zu einem neuen String verketten. Beachte dabei, dass C#-Strings unveränderlich (immutable) sind und die gängigen Operatoren und Funktionen immer einen neuen String erzeugen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">string fullName = firstName + " " + lastName;</pre>



<p>Das war die einfachste Art, einen String zu formatieren. Aber was, wenn es etwas komplexer sein muss? Was, wenn der Nutzer sein eigenes Format festlegen können soll?</p>



<h2 class="wp-block-heading">Einen String in C# &#8222;auf die alte Art&#8220; formatieren</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/08/Formatting-csharp-strings-using-string-class-format-method.png"><img decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/08/Formatting-csharp-strings-using-string-class-format-method.png" alt="C# Strings mit der String.Format-Methode formatieren" class="wp-image-11670" title="C# Strings mit der String.Format-Methode formatieren"/></a><figcaption class="wp-element-caption">C# Strings mit der String.Format-Methode formatieren</figcaption></figure>



<p>Das Beispiel von oben war recht simpel und bietet dem Nutzer keine Anpassungsmöglichkeit. Wenn jemand dein Programm nutzt und die Reihenfolge ändern möchte, müsste er Vor- und Nachname selbst tauschen. Klar, manchmal ist das nicht nötig, aber gut zu wissen!</p>



<p>Schauen wir uns nun eine Hilfsfunktion der <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.string?view=net-6.0" target="_blank" rel="noreferrer noopener">String-Klasse</a></strong> des .NET Frameworks an, die einfach &#8222;Format&#8220; heißt. Wir verwenden diese Funktion, um den gleichen vollständigen Namen wie oben zu erzeugen.</p>



<p>Dazu schauen wir uns zunächst die Funktionsparameter an. Es gibt <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.string.format?view=net-6.0" target="_blank" rel="noreferrer noopener">verschiedene Überladungen</a></strong>, aber wir konzentrieren uns auf die mit einem String als erstem Parameter und einem Object-Array als zweitem. Der erste Parameter erwartet eine Art Formatierungs-&#8222;Formel&#8220;. Der zweite erwartet die Objekte, die an den entsprechenden Stellen eingesetzt werden. Das geschieht über geschweifte Klammern mit dem jeweiligen Index des Objekts.</p>



<h3 class="wp-block-heading">Einen String dynamisch formatieren</h3>



<p>Wir können beliebige Objekte (aktuell zwei Strings) kommagetrennt übergeben. Im nächsten Beispiel übergebe ich die beiden Namensteile. Die Variable firstName hat dann den Index 0, lastName den Index 1.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">string firstName = "John";
string lastName= "Doe";
string fullName = string.Format("{0} {1}", firstName, lastName);</pre>



<p>Jetzt könnte der Nutzer bei Bedarf ein eigenes Format eingeben. Im folgenden Beispiel habe ich die Reihenfolge der Namen getauscht. Das erzeugt einen neuen String mit dem Inhalt &#8222;Doe John&#8220; statt &#8222;John Doe&#8220;.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// z.B. aus einer TextBox übernommen
string userWantedFormat = "{1} {0}";
string firstName = "John";
string lastName= "Doe";
string fullName = string.Format(format, firstName, lastName);</pre>



<p>Du könntest die übergebenen Werte natürlich auch dynamisch über eine Liste steuern und Einträge hinzufügen oder weglassen. Die Funktion akzeptiert auch eine Liste beliebiger Objekte als Parameter.</p>



<h2 class="wp-block-heading">C# String Format mit Interpolation</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/08/Using-String-interpolation-in-csharp.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/08/Using-String-interpolation-in-csharp.png" alt="String-Interpolation in C# verwenden" class="wp-image-11672" title="String-Interpolation in C# verwenden"/></a><figcaption class="wp-element-caption">String-Interpolation in C# verwenden</figcaption></figure>



<p>Ich bevorzuge den modernen Ansatz namens &#8222;String-Interpolation&#8220;. Damit kannst du die gewünschten Werte direkt an der richtigen Stelle im String platzieren. Bauen wir das obige Beispiel damit nach.</p>



<p>Neben der direkten Positionierung ist es auch viel einfacher zu erkennen, was wo steht. Im vorherigen Beispiel konnten wir nur sagen: &#8222;Setze den String mit Index 0 hierhin&#8220;, aber was passiert, wenn sich der Index ändert? Weißt du dann noch, welche Position korrekt ist?</p>



<p>Hier das Beispiel von oben, jetzt mit String-Interpolation. Dafür setzen wir ein Dollarzeichen vor den String und geben die Variablennamen in geschweiften Klammern an. Meiner Meinung nach ist das deutlich einfacher und übersichtlicher als alle bisherigen Varianten.</p>



<p>So können wir auch die lästigen Anführungszeichen und &#8222;+&#8220;-Zeichen vergessen. Weniger Code, bessere Lesbarkeit.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">string firstName = "John";
string lastName = "Doe";
string fullName = $"{firstName} {lastName}";</pre>


<div style="box-sizing:border-box;margin:36px 0;border-radius:12px;overflow:hidden;background:#1a1a2e;position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
  <div style="position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.03) 1px,transparent 1px);background-size:40px 40px;pointer-events:none;"></div>
  <div style="position:absolute;top:-60px;right:-60px;width:240px;height:240px;background:radial-gradient(circle,rgba(230,126,34,0.18) 0%,transparent 70%);pointer-events:none;"></div>
  <div style="position:relative;padding:32px 28px;">

        <div style="display:inline-block;font-size:11px;font-weight:700;letter-spacing:2.5px;text-transform:uppercase;color:#e67e22;margin-bottom:14px;border:1px solid rgba(230,126,34,0.35);border-radius:4px;padding:3px 10px;">Auftrag?</div>
    
        <p style="margin:0 0 10px 0;font-size:clamp(17px,4vw,21px);font-weight:700;color:#ffffff;line-height:1.35;">C#-Entwicklung für dein Projekt?</p>
    
        <p style="margin:0 0 24px 0;font-size:14px;color:rgba(255,255,255,0.65);line-height:1.7;max-width:540px;">Ich arbeite täglich mit C# und .NET. Ob Formatierungslogik, Architektur oder komplette Anwendungen – schreib mir einfach.</p>
    
    <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;">

            <a href="https://robbelroot.de/kontakt/"
         style="display:inline-block;padding:12px 24px;background:#e67e22;color:#ffffff;font-size:14px;font-weight:700;text-decoration:none;border-radius:7px;letter-spacing:0.3px;transition:background .2s ease;white-space:nowrap;"
         onmouseover="this.style.background='#cf6d17'"
         onmouseout="this.style.background='#e67e22'"
      >→ Projekt anfragen</a>
      
      
    </div>
  </div>
</div>
	


<h2 class="wp-block-heading" id="how-to-format-numbers-and-currencies">Zahlen und Währungen formatieren</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/08/How-to-format-numbers-to-strings-in-csharp.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/08/How-to-format-numbers-to-strings-in-csharp.png" alt="Zahlen in C# als Strings formatieren" class="wp-image-11706" title="Zahlen in C# als Strings formatieren"/></a><figcaption class="wp-element-caption">Zahlen in C# als Strings formatieren</figcaption></figure>



<p>Nachdem wir bisher nur mit dem einfachen Namensbeispiel gearbeitet haben, gehen wir jetzt einen Schritt weiter. Strings zu Strings formatieren ist nicht schwer, aber schauen wir uns an, wie es mit komplexeren Typen aussieht. Der erste etwas komplexere (aber trotzdem einfache) Typ ist eine gewöhnliche Zahl, wie die Rechnungssumme vom Anfang dieses Beitrags (die 14).</p>



<p>In der Regel zeigt man den Gesamtbetrag einer Rechnung mit zwei Dezimalstellen an. Neben den Dezimalstellen verwendet man z. B. auch das Euro-Zeichen. Versuchen wir die einfache Darstellung der Zahl 14 aus dem Bild oben.</p>



<p>Dafür können wir eine der bereits gezeigten Methoden verwenden:</p>



<ul class="wp-block-list">
<li>manuelle Formatierung</li>



<li>die Format-Methode der String-Klasse</li>



<li>String-Interpolation</li>
</ul>



<h3 class="wp-block-heading">Formatieren mit der &#8222;ToString&#8220;-Basisfunktion</h3>



<p>Zunächst ein Beispiel mit der &#8222;manuellen&#8220; Variante über die typische &#8222;ToString&#8220;-Funktion, die von der Basisklasse Object geerbt wird. Wir verwenden die Überladung, bei der man ein Format als String angeben kann. Das Format &#8222;N2&#8220; steht für: Zahl mit zwei Dezimalstellen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">decimal totalNet = 14.95M;
string displayValue = totalNet.ToString("N2");
// Ergebnis: "14.95" bei en-US Systemeinstellung</pre>



<h3 class="wp-block-heading" id="using-string-format-or-interpolation">Mit string.Format oder Interpolation</h3>



<p>Das gleiche Ergebnis lässt sich auch mit den anderen beiden Techniken erreichen. Hier beide Varianten:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">decimal totalNet = 14.95M;
// mit string.Format
string displayValue = string.Format(totalNet, "{0:N2}");
// mit String-Interpolation
string displayValue = $"{totalNet:N2}";</pre>



<h3 class="wp-block-heading">Eine bestimmte Kultur / Sprache / Locale angeben</h3>



<p>Wie im Kommentar zu sehen, erhältst du einen Wert wie &#8222;14.95&#8220;. Beachte, dass das Ergebnis von der Spracheinstellung abhängt. Du kannst über den Parameter &#8222;FormatProvider&#8220; auch z. B. die deutsche Spracheinstellung vorgeben.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Import nicht vergessen!
// using System.Globalization;
// entweder so
CultureInfo deDeCulture = new CultureInfo("de-DE");
// oder so
CultureInfo enUsCulture = new CultureInfo("en-US");
decimal totalNet = 14.95M;
// als zweiten Parameter übergeben
string displayValue = totalNet.ToString("N2", deDeCulture);
// Ergebnis: en-US = 14.95, de-DE = 14,95</pre>



<p>Um String-Interpolation mit einer Kultur zu verwenden, kannst du einen &#8222;FormattableString&#8220; erstellen und diesen statt eines normalen Strings verwenden.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">decimal totalNet = 14.95M;
// erzeugt automatisch einen FormattableString!
FormattableString displayValue = $"Der Gesamtpreis beträgt {totalNet:N2}.";
CultureInfo enUsCulture = new CultureInfo("en-US");
string message = displayValue.ToString(enUsCulture);
// en-US = 14.95, de-DE = 14,95</pre>



<h3 class="wp-block-heading">Die Kultur global setzen, nicht pro Aufruf</h3>



<p>Im nächsten Schritt kannst du es noch einfacher machen, je nach Anwendungsfall, indem du die &#8222;CultureInfo&#8220; global setzt. Damit überschreibst du die systemspezifische Standardeinstellung:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Import nicht vergessen
// using System.Threading;
CultureInfo deDeCulture = new CultureInfo("de-DE");
CultureInfo enUsCulture = new CultureInfo("en-US");
// System-Standard überschreiben
Thread.CurrentThread.CurrentCulture = enUsCulture;</pre>



<p>Alle nachfolgenden Aufrufe von Formatierungsfunktionen wie &#8222;ToString&#8220; verwenden nun &#8222;enUsCulture&#8220; als Standard (anstelle der Systemvorgabe).</p>



<h3 class="wp-block-heading">Währungsformatierte Strings ausgeben</h3>



<p>Nach der normalen Zahlenformatierung können wir nun eine einfache währungsbezogene Zahl anzeigen. Das funktioniert fast identisch, nur mit einem anderen Buchstaben. Statt &#8222;N2&#8220; (Zahl mit 2 Dezimalstellen) verwende ich &#8222;C2&#8220; (Währung mit 2 Dezimalstellen).</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// siehe auch die vorherigen Beispiele mit string.Format und manueller Variante
FormattableString displayValue = $"Der Gesamtpreis beträgt {totalNet:C2}.";
CultureInfo enUsCulture = new CultureInfo("en-US");
string message = displayValue.ToString(enUsCulture);</pre>



<h2 class="wp-block-heading">DateTimes oder komplexere Objekte formatieren</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/08/How-to-format-datetimes-or-custom-objects.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/08/How-to-format-datetimes-or-custom-objects.png" alt="DateTimes oder eigene Objekte formatieren" class="wp-image-11740" title="DateTimes oder eigene Objekte formatieren"/></a><figcaption class="wp-element-caption">DateTimes oder eigene Objekte formatieren</figcaption></figure>



<p>Im nächsten Abschnitt schauen wir uns das Formatieren von komplexeren Objekten an. Zum Beispiel die <strong>DateTime</strong>-Klasse und eventuell auch eigene Klassen.</p>



<p>Was, wenn du einen Kunden hast, der entweder Privat- oder Geschäftskunde sein kann, und du per C# String Format dessen Anzeige steuern willst? Zeigst du den Firmennamen oder Vor- und Nachname an?</p>



<h3 class="wp-block-heading">DateTimes formatieren</h3>



<p>Beginnen wir mit ein paar Beispielen zur Formatierung einer C# DateTime-Instanz. Ich bleibe bei der String-Interpolation, du kannst aber auch die anderen Techniken <strong><a href="#using-string-format-or-interpolation">von oben</a></strong> verwenden. Nach einem einfachen Datumsstring geht es weiter mit Monats- und Zeitformaten.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// aktuelles Datum und Uhrzeit als Beispiel
DateTime now = DateTime.Now;
// typisch deutsches Datum - z.B. 30.03.2023
string displayValue = $"{now:dd.MM.yyyy}";
// typisch englisches Datum - Backslashes beachten, alternativ
// die doppelten Backslashes weglassen und den @-Prefix nutzen: @$
string displayValue = $"{now:MM\\dd\\yyyy}";
// mit Uhrzeit arbeiten
string displayTimeValue = @$"{now:HH:mm}";</pre>



<h3 class="wp-block-heading">Eigene Objekte wie eine Kunden-Klasse formatieren</h3>



<p>In diesem letzten Abschnitt schauen wir uns das Formatieren einer eigenen Kunden-Klasse an. Die Klasse ist bewusst einfach gehalten mit nur wenigen Properties. Wir erstellen zwei &#8222;Typen&#8220; von Kunden: Geschäftskunden und Privatkunden. Der Geschäftskunde hat nur seinen Firmennamen, der Privatkunde Vor- und Nachnamen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class Customer
{

  public string Company { get; set; }

  public string FirstName { get; set; }

  public string LastName { get; set; }

  public Customer(string company)
  {
    Company = company;
  }

  public Customer(string firstName, string lastName)
  {
    FirstName = firstName;
    LastName = lastName;
  }

}</pre>



<p>Dann können wir einen Privat- und einen Geschäftskunden so erstellen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Customer privateCustomer = new Customer("John", "Doe");
Customer businessCustomer = new Customer("Doe Max Profit ltd.");</pre>



<p>Wenn du sie jetzt so formatierst, erhältst du etwas wie &#8222;Customer: ProjektName.ClassName&#8220;. So sehen Objekte ohne Überschreibung der &#8222;ToString&#8220;-Funktion aus.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// enthält z.B. Customer: ProjektName.Customer
string text = $"Customer: {privateCustomer}";</pre>



<p>Wir müssen also nur die &#8222;ToString&#8220;-Funktion überschreiben. In diesem Beispiel priorisiere ich den Firmennamen. Ist keiner vorhanden, gebe ich den vollständigen Namen zurück. Wenn du über mehrere Kunden iterieren musst, schau dir <a href="https://robbelroot.de/blog/csharp-for-each-iterating-the-objective-way/">C# ForEach</a> an.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">public class Customer
{

  // ...
  // restlicher Code von oben
  // ...

  public override ToString()
  {
    if (string.IsNullOrEmpty(Company)) {
      return Company;
    }
    return $"{FirstName} {LastName}";
  }
}</pre>



<p>Schau dir nun die Ergebnisse der folgenden Codezeilen an:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Customer privateCustomer = new Customer("John", "Doe");
Customer businessCustomer = new Customer("Doe Max Profit ltd.");
// enthält Customer: John Doe
string text = $"Customer: {privateCustomer}";
// enthält Customer: Doe Max Profit ltd.
string text = $"Customer: {businessCustomer}";</pre>



<p>Wie in den Kommentaren zu sehen, erhalten wir nun unterschiedliche und besser lesbare Ergebnisse.</p>



<h2 class="wp-block-heading">FAQ</h2>



<div class="schema-faq wp-block-yoast-faq-block"><div class="schema-faq-section" id="faq-cs-format-de-1"><strong class="schema-faq-question">Was ist der Unterschied zwischen String.Format und String-Interpolation in C#?</strong> <p class="schema-faq-answer">Beide liefern das gleiche Ergebnis. String-Interpolation (mit dem <code>$</code>-Prefix) ist lesbarer, weil du Variablen direkt im String platzierst statt auf Indexnummern zu verweisen. Für neuen Code ist Interpolation die bessere Wahl.</p> </div> <div class="schema-faq-section" id="faq-cs-format-de-2"><strong class="schema-faq-question">Wie formatiere ich eine Zahl mit zwei Dezimalstellen in C#?</strong> <p class="schema-faq-answer">Verwende den Format-Specifier <code>N2</code>, z. B. <code>totalNet.ToString("N2")</code> oder <code>$"{totalNet:N2}"</code> per String-Interpolation. Das Ergebnis hängt von der aktiven CultureInfo ab (<code>14.95</code> bei en-US, <code>14,95</code> bei de-DE).</p> </div> <div class="schema-faq-section" id="faq-cs-format-de-3"><strong class="schema-faq-question">Wie zeige ich ein Währungssymbol bei der Formatierung in C# an?</strong> <p class="schema-faq-answer">Verwende den Format-Specifier <code>C</code>, z. B. <code>$"{price:C2}"</code>. Das Währungssymbol wird durch die aktive CultureInfo bestimmt: <code>$</code> bei en-US, <code>€</code> bei de-DE.</p> </div> <div class="schema-faq-section" id="faq-cs-format-de-4"><strong class="schema-faq-question">Wie formatiere ich ein DateTime in ein bestimmtes Muster in C#?</strong> <p class="schema-faq-answer">Verwende Format-Specifier in <code>ToString</code> oder String-Interpolation, z. B. <code>$"{now:dd.MM.yyyy}"</code> für ein Datum oder <code>$"{now:HH:mm}"</code> für die Uhrzeit. Du kannst Muster frei kombinieren.</p> </div> </div>



<h2 class="wp-block-heading">Fazit</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/08/Wrapping-up.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/08/Wrapping-up.png" alt="Zusammenfassung" class="wp-image-11757" title="Zusammenfassung"/></a><figcaption class="wp-element-caption">Zusammenfassung</figcaption></figure>



<p>C# bietet drei Wege zur String-Formatierung: manuelle Verkettung, String.Format und String-Interpolation. Für neuen Code empfehle ich Interpolation, da sie am lesbarsten ist. Verwende <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.globalization.cultureinfo?view=net-10.0" target="_blank" rel="noreferrer noopener">CultureInfo</a></strong>, wenn deine Anwendung mehrere Sprachen unterstützen muss. Für ein weiteres praktisches C#-Beispiel schau dir <a href="https://robbelroot.de/blog/how-to-use-the-csharp-linq-sum-function/">C# LINQ Sum</a> an.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/csharp-string-format/">C# String Format – Interpolation, Zahlen, Datum (2026)</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/csharp-string-format/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
