<?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>klick Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/klick/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Thu, 18 Jan 2024 00:52:07 +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>klick Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Eigene WPF Commands in MVVM VB.NET &#038; C# &#8211; der 2024 Guide</title>
		<link>https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/</link>
					<comments>https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sat, 07 Jan 2023 11:32:01 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[C# (C Sharp)]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[ausführen]]></category>
		<category><![CDATA[befehle]]></category>
		<category><![CDATA[bindung]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[command]]></category>
		<category><![CDATA[commandparameter]]></category>
		<category><![CDATA[commands]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[datenbindung]]></category>
		<category><![CDATA[handler]]></category>
		<category><![CDATA[klick]]></category>
		<category><![CDATA[knopf]]></category>
		<category><![CDATA[knöpfe]]></category>
		<category><![CDATA[modern]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[parameter]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[wpf]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=13398</guid>

					<description><![CDATA[<p>Nutze WPF Commands, vermeide &#8222;Button1_Click&#8220; &#38; Co. Im heutigen Beitrag schauen wir uns das Thema &#8222;eigene WPF Commands&#8220;, bzw. die passende Schnittstelle &#8222;ICommand&#8220; an. Damit werden wir der besonders aus Winforms-Zeiten (Windows Forms) bekannten Vermischung von Design und Quellcode entfliehen. Dazu schauen wir uns erst die Basis der &#8222;ICommand&#8220;-Schnittstelle an &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/">Eigene WPF Commands in MVVM VB.NET &#038; C# &#8211; der 2024 Guide</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Eigene-Commands-in-VB.NET-WPF-MVVM-mit-PasswordBox-Tricks-und-Co.-Guide-Thumbnail.png"><img fetchpriority="high" decoding="async" width="1280" height="720" src="https://robbelroot.de/wp-content/uploads/2023/01/Eigene-Commands-in-VB.NET-WPF-MVVM-mit-PasswordBox-Tricks-und-Co.-Guide-Thumbnail.png" alt="Eigene Commands in VB.NET WPF MVVM mit PasswordBox, Tricks und Co. - Guide" class="wp-image-13403" title="Eigene Commands in VB.NET WPF MVVM mit PasswordBox, Tricks und Co. - Guide"/></a><figcaption class="wp-element-caption">Eigene Commands in VB.NET WPF MVVM mit PasswordBox, Tricks und Co. &#8211; Guide</figcaption></figure>






<h2 class="wp-block-heading">Nutze WPF Commands, vermeide &#8222;Button1_Click&#8220; &amp; Co.</h2>



<p>Im heutigen Beitrag schauen wir uns das Thema &#8222;eigene WPF Commands&#8220;, bzw. die passende Schnittstelle &#8222;ICommand&#8220; an. Damit werden wir der besonders aus Winforms-Zeiten (Windows Forms) bekannten Vermischung von Design und Quellcode entfliehen. Dazu schauen wir uns erst die Basis der &#8222;ICommand&#8220;-Schnittstelle an und erstellen auch anschließend eine wiederverwendbare Klasse – wir haben schließlich keinen Bock, alles 10x zu schreiben! Um alles zu verstehen, geht es hier und da natürlich noch einmal Richtung Details, aber gut, so viel Zeit muss sein, wenn man nicht nur &#8222;Copy &amp; Paste&#8220;-Master sein möchte :)!</p>



<p class="info-banner"><strong>&#x1f4a1;</strong> <strong>Hinweis</strong>: Nutze gerne <strong><a href="#toc_container">das Inhaltsverzeichnis</a></strong>, um an passende Stellen zu springen, da es sich hierbei um ein ausführliches Thema handelt, Welches man nicht &#8222;mal eben&#8220; besprechen kann. Falls Du z. B. nur <strong><a href="#finale-delcommand-basisklasse">eine wiederverwendbare Command-Basisklasse</a></strong> benötigst, findest Du Diese weiter unten. Vielleicht möchtest Du auch einen Blick auf <strong><a href="#downloads">die Downloads-Sektion</a></strong> werfen?</p>



<style>
.info-banner {
    background: #03a9f4;
    padding: 2em;
    border-radius: 0.5em;
    color: whitesmoke;
}
.info-banner a {
    color: #FED766;
}
</style>



<p>In diesem Beitrag werden wir synchrone Commands besprechen, die asynchrone Variante werden wir im Detail, in einem der nächsten Beiträge angehen. Ebenso wird das Thema &#8222;Login&#8220; nur als Beispiel thematisiert und nicht vollständig realisiert. Allgemein möchte ich erreichen, dass Du hier rausgehen und &#8222;Nice, ich habe Commands verstanden&#8220; sagen kannst :)!</p>



<h2 class="wp-block-heading">Kurzfassung – .NET WPF Commands in MVVM</h2>



<p>Wenn Du es eilig hast, hier die <strong>Kurzfassung</strong> über .NET MVVM Commands in WPF:</p>



<ul class="wp-block-list">
<li><strong>Ersetze </strong>z. B. die typischen Click-<strong>Handler </strong>von Buttons <strong>durch </strong>passende Datenbindungen an sogenannte <strong>Commands</strong>. Beachte jedoch, dass Commands nicht nur von Buttons, sondern z. B. auch von Kontextmenüs unterstützt werden!</li>



<li>Dazu musst Du Deinem <strong>View </strong>in erster Linie einen <strong>Datenkontext geben</strong>, damit es weiß, <strong>woher </strong>es die &#8222;<strong>Dinge</strong>&#8220; durch Datenbindung <strong>bekommen </strong>kann.</li>



<li><strong>Sage </strong>in Deinem <strong>Button</strong>-XAML dann via <strong>Command-Eigenschafts-Bindung</strong>, dass Du das &#8222;<strong>LoginCommand</strong>&#8220; <strong>verwenden </strong>möchtest &#8211; voilà!</li>



<li><strong>Implementiere </strong>im nächsten Schritt die &#8222;<strong>ICommand</strong>&#8222;-Schnittstelle und <strong>erstelle </strong>danach in Deinem Datenkontext eine passende, bindbare <strong>Eigenschaft</strong>, z. B. &#8222;<strong>LoginCommand</strong>&#8220; zur Verfügung.</li>



<li><strong>Instanziiere </strong>die <strong>Command</strong>-basierte Eigenschaft nun z. B. <strong>in </strong>Deinem <strong>ViewModel</strong>&#8211;<strong>Konstruktor</strong>.</li>



<li><strong>Übergib</strong> manuelle oder gebundene <strong>Parameter</strong>, indem Du <strong>an </strong>die <strong>CommandParameter</strong>&#8211;<strong>Eigenschaft </strong>des (z. B.) Buttons bindest.</li>
</ul>



<p>Damit Du die Implementierung allerdings nicht hunderte Male und für z. B. jeden Knopf wiederholen musst, würde ich Dir eine Abstraktion durch eine Basisklasse vorschlagen. Eine derartige Klasse (für VB.NET &amp; C#) findest Du natürlich auch hier im Beitrag. Scrolle dazu einfach zu &#8222;<strong><a href="#wiederverwendbare-klasse">eine wiederverwendbare Command-Basisklasse</a></strong>&#8222;, oder direkt zu <strong><a href="#downloads">den Downloads</a></strong>.</p>



<h2 class="wp-block-heading">Beitrag als Video ansehen</h2>



<p>Wenn Du diesen Beitrag lieber im Videoformat genießen möchtest, kannst Du natürlich auch das <strong><a href="https://youtu.be/TZD6259Mma8" target="_blank" rel="noreferrer noopener">folgende Video</a></strong> (vielleicht auch ergänzend) ansehen. Besonders die Hinweise bezüglich der &#8222;PasswordBox&#8220; sind sehr wichtig!</p>


<div class="async-youtube" data-embed="TZD6259Mma8" data-alt="">
    <div class="play-button"></div>      
  </div>



<h2 class="wp-block-heading" id="projekt-und-ordnerstruktur">Projekt- und Ordnerstruktur</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Projekt-und-Ordnerstruktur-–-VB.NET-WPF-Commands-in-MVVM_640px.png"><img decoding="async" width="640" height="427" src="https://robbelroot.de/wp-content/uploads/2023/01/Projekt-und-Ordnerstruktur-–-VB.NET-WPF-Commands-in-MVVM_640px.png" alt="Projekt- und Ordnerstruktur – VB.NET WPF Commands in MVVM" class="wp-image-13421" title="Projekt- und Ordnerstruktur – VB.NET WPF Commands in MVVM"/></a><figcaption class="wp-element-caption">Projekt- und Ordnerstruktur – VB.NET WPF Commands in MVVM</figcaption></figure>



<p>Bevor wir mit dem eigentlichen Thema &#8222;WPF Commands in MVVM&#8220; loslegen können, legen wir uns als Erstes unsere Projektstruktur zurecht. Eine vernünftige Ordner- und Organisationsstruktur ist natürlich nicht nur nützlich, wenn man allein arbeitet, um z. B. immer in den gewohnten Ablauf hineinzukommen. Es hilft uns zusätzlich auch dabei, falls wir mal etwas outsourcen, bzw. jemanden um Hilfe bitten müssen – und das kommt häufig schneller vor, als man denkt! Wer will sich außerdem in seinem eigenen Code immer den Ast absuchen müssen, nur weil es jedes Mal anders aussieht? Keiner!</p>



<p>Natürlich könnte ich jetzt hier auch alles wieder von vorn erzählen, möchte es aber im Sinne des Entwicklers (Don&#8217;t repeat yourself &#8211; wiederhole dich nicht) vermeiden. Schaue Dir den Basis-Projektaufbau daher gerne in meinem Beitrag <strong><a href="https://robbelroot.de/blog/ein-wpf-mvvm-projekt-aufsetzen-guide/" target="_blank" rel="noreferrer noopener">&#8222;Wie setzt man ein VB.NET, bzw. WPF MVVM-Projekt auf&#8220;</a></strong> an.</p>



<h2 class="wp-block-heading">Die Rollenverteilung in .NET WPF MVVM</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/07/MVVM-getrennte-Entwickler-Designer-Rollen.gif"><img decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/07/MVVM-getrennte-Entwickler-Designer-Rollen.gif" alt="Trennung von Designern und Entwicklern" class="wp-image-5074"/></a><figcaption class="wp-element-caption">Trennung von Rollen im MVVM-Entwurfsmuster</figcaption></figure>



<p>Da dieser Beitrag die Verwendung von Commands im Fokus hat, verstehe bitte, dass ich nicht zu tief in das &#8222;Model-View-ViewModel&#8220;-Entwurfsmuster selbst abtauchen kann. Allerdings ist für die Verwendung von WPF Commands natürlich ein gewisses Grundverständnis der MVVM-Architektur erforderlich. Besuche für eine erweiterte Erklärung gerne meinen <strong><a href="https://robbelroot.de/blog/mvvm-csharp/" target="_blank" rel="noreferrer noopener">Beitrag zum MVVM-Entwurfsmuster</a></strong>, auch wenn Dieser C#-geprägt ist, sind alle Erkenntnisse natürlich auch bei VB.NET analog.</p>



<p>Grundsätzlich geht es bei dieser Strukturierung von modernen .NET Applikationen (oder auch Applikationen im Allgemeinen) anhand des MVVM-Musters darum, eine saubere Rollentrennung zu erreichen. Insbesondere spricht man hier von der Trennung von Benutzeroberfläche und Geschäftslogik – woran meist verschiedene Personen wie Designer und Entwickler arbeiten. Dies bietet nicht nur die Möglichkeit, sich fast ganz auf seine Rolle konzentrieren zu können, sondern auch ganz andere praktische Vorteile. So erreicht man durch die einfachere Austauschbarkeit von &#8222;Views&#8220; und &#8222;ViewModels&#8220; etwa eine erhöhte Test- und Wartbarkeit seiner Software im Allgemeinen.</p>



<h3 class="wp-block-heading">Das View – die Aufgabe des Designers</h3>



<p>Je nach Herangehensweise (also View-, oder ViewModel-First) geht z. B. der Designer hin und entwirft nach etwaigen Wireframing-Prozessen die gewünschte Oberfläche mit Hilfe der XAML-Auszeichnungssprache. Mit dem Kunden wurden also ggf. vorherige Absprachen (mit Skizzen &#8211; Wireframes) getroffen, Welche das ungefähre Layout und Design zumindest grob bestimmen sollen. Dies kann dann z. B. ohne eine Zeile Code geschrieben zu haben wie gleich folgend aussehen und eine gemeinsame Basis / einen gemeinsamen Konsens bilden. Zugegebenermaßen ist das folgende Beispiel schon eher auf einem &#8222;Non-Plus-Ultra&#8220;-Level, da man – je nach Unternehmensgröße – eher ein &#8222;mach&#8216; Mal&#8220; geliefert bekommt. Aber gut, träumen darf man als Entwickler noch, oder!?</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/MVVM-WPF-XAML-Wireframing-Prozess.png"><img loading="lazy" decoding="async" width="2880" height="1600" src="https://robbelroot.de/wp-content/uploads/2023/01/MVVM-WPF-XAML-Wireframing-Prozess.png" alt="MVVM WPF XAML Wireframing Prozess – Quelle: moqups Wireframing Tool" class="wp-image-13479" title="MVVM WPF XAML Wireframing Prozess"/></a><figcaption class="wp-element-caption">MVVM WPF XAML Wireframing Prozess – Quelle: moqups.com Wireframing Tool</figcaption></figure>



<p>Wenn unsere Wünsche daher also wahr werden, haben die Designer die Möglichkeit, die skizzierten Wünsche des Kunden relativ unabhängig vom Entwickler (-Team) in XAML umsetzen zu können. Ganz im Stil von WPF und Co. verwendet man hier Datenbindungen, also XAML Binding-Anweisungen, wie z. B.:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;TextBox Text="{Binding WelcomeMessage}" /></pre>



<p>Den Designern kann und soll es an dieser Stelle egal sein, wie genau die &#8222;WelcomeMessage&#8220; erschaffen und verändert wird, solange Sie daran binden können &#8211; ergo sich an die WPF-Mechanismen gehalten wird. Viele verkaufen den utopischen Traum des &#8222;Solo-Separat-Entwickelns&#8220; zu gern, allerdings muss natürlich trotzdem Austausch zwischen Entwicklern und Designern stattfinden. Ein &#8222;wir arbeiten vollkommen getrennt voneinander&#8220; ist also nicht zu 100% möglich, ABER eben viel viel einfacher. Die Designer können ja schließlich z. B. auch nicht raten, ob unsere &#8222;IsSelected&#8220;-Eigenschaft nun eben sinnigerweise so, oder &#8222;Selected&#8220; heißt. Je öfter man zusammenarbeitet, desto leichter erschließen sich solche Muster natürlich in Zukunft und man kann immer unabhängiger, gar blind zusammenarbeiten.</p>



<h3 class="wp-block-heading">Der Entwickler, die ViewModels, Geschäftslogik und Co.</h3>



<p>Nachdem wir als Entwickler – im Optimalfall – also nun unsere Wireframes bekommen haben, können nun auch wir ziemlich isoliert / separat tätig werden. Wir entwerfen die passenden ViewModel-Klassen zu den gezeigten Oberflächen, Welche &#8222;INotifyPropertyChanged&#8220; und Co. verwenden, um durch die Datenbindungen zu kommunizieren. Schaue Dir hierzu gerne <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/" target="_blank" rel="noreferrer noopener">meinen Beitrag zum Thema &#8222;INotifyPropertyChanged&#8220;</a></strong> an. Bei Bedarf erschaffen wir Test-ViewModels, Welche wir durch die neue Herangehensweise, ohne Probleme und Aufwand austauschen und testen können.</p>



<p>Wie erwähnt möchte ich den Exkurs in Richtung &#8222;Model-View-ViewModel-Entwurfsmuster&#8220; nicht zu weit treiben, daher gehe ich hier nicht weiter auf z. B. Models ein. Ich denke sowieso, dass das nicht zielführend wäre, denn zu viel Input ist ja auch schlecht, oder? &#8222;Kleine&#8220; Häppchen machen dann schon eher den Appetit :)! </p>



<h2 class="wp-block-heading">Ein kleines Login-Fenster-Beispiel für WPF Commands</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Ein-erstes-eigenes-WPF-Command-in-MVVM.png"><img loading="lazy" decoding="async" width="640" height="423" src="https://robbelroot.de/wp-content/uploads/2023/01/Ein-erstes-eigenes-WPF-Command-in-MVVM.png" alt="Ein erstes, eigenes WPF Command in MVVM" class="wp-image-13507" title="Ein erstes, eigenes WPF Command in MVVM"/></a><figcaption class="wp-element-caption">Ein erstes, eigenes WPF Command in MVVM</figcaption></figure>



<p>Nach dem kleinen Exkurs von oben, schauen wir uns nun die weitere Reise in Richtung Commands an. Dazu bauen wir uns im nächsten Schritt eine kleine Login-Oberfläche (Achtung, billig..), Welche wie gleich folgend aussehen könnte. Hier werden wir auch direkt aus einer Art Designer-Perspektive agieren, also wir arbeiten in erster Linie &#8222;nur&#8220; am XAML-Code selbst.</p>



<p>Wir tun hier einfach mal so, als hätten wir ein passendes Wireframe vom Kunden vorliegen.. Was macht also ggf. in erster Linie eine Login-Oberfläche aus? Naja, wir brauchen:</p>



<ul class="wp-block-list">
<li>Eine Textbox für die Eingabe des Nutzers / E-Mail-Adresse</li>



<li>Ein Label / Textblock für diese Textbox, sonst weiß der Nutzer nicht was das soll</li>



<li>Eine PasswordBox für die Eingabe des Passworts (beachte hier die Hinweise)</li>



<li>Auch hierfür einen Textblock</li>



<li>Einen Button, wie soll der Benutzer sonst &#8222;Login-Versuch durchführen&#8220; triggern</li>



<li>ggf. weiteren Kram, wie &#8222;Passwort vergessen&#8220; &#8211; lassen wir hier aber aus..</li>
</ul>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Login-Fenster-mit-WPF-Commands-in-MVVM.png"><img loading="lazy" decoding="async" width="789" height="446" src="https://robbelroot.de/wp-content/uploads/2023/01/Login-Fenster-mit-WPF-Commands-in-MVVM.png" alt="Login-Fenster mit WPF Commands in MVVM" class="wp-image-13511" title="Login-Fenster mit WPF Commands in MVVM"/></a><figcaption class="wp-element-caption">Login-Fenster mit WPF Commands in MVVM</figcaption></figure>



<p>Bitte bedenke auch an dieser Stelle – wie oben angekündigt –, dass wir hier kein vollständiges Login-Beispiel realisieren können, da der Beitrag auch so schon lang genug wird &#x1f609;! Einen Login werde ich ggf. mal in einem anderen Beitrag separat behandeln und dort dann ausführen.</p>



<h3 class="wp-block-heading">Datenbindungen des Login-Fensters</h3>



<p>Nachdem wir im obigen Schritt die grundsätzlich benötigten Steuerelemente angemerkt haben, brauchen wir – für MVVM selbstverständlich – auch passende Datenbindungen. Ansonsten wüssten weder die Textboxen, woher Sie Ihren Text bekommen, oder gar &#8222;hinschicken&#8220; sollen. Ebenso hätte der Anmelden-Knopf keine Ahnung, was beim Klick passieren soll (Spoiler: Ein Command ausführen).</p>



<p>Der Designer wird an dieser Stelle hier irgendwie vorher (mit Kunden und Entwicklern) besprochen haben, dass es im ViewModel so etwas namens &#8222;User&#8220; geben muss. Dabei handelt es sich genauer genommen um eine String-Eigenschaft, welche den dementsprechenden Text für die Textbox – also den Benutzer – beinhalten muss. Ebenso muss diese Eigenschaft bei Code-technischen Änderungen nach außen kommunizieren, dass Sie sich geändert hat. Dies geht wie vermutlich bekannt über &#8222;INotifyPropertyChanged&#8220;, was hier allerdings nicht weiter Thema sein wird. Hier nochmal erneut der Hinweis auf <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/">meinen &#8222;INotifyPropertyChanged&#8220;-Beitrag mit &#8222;PropertyChanged&#8220;-Basisklasse</a></strong>.</p>



<p>Schaue Dir nun einmal den XAML-Code zum Fenster an, beachte, dass Du die obigen <strong><a href="#projekt-und-ordnerstruktur">&#8222;Projekt- und Ordnerstruktur&#8220;-Schritte</a></strong> korrekt abgeschlossen hast. Ansonsten wirst Du hier vermutlich Probleme mit Namespace und Co. bekommen. Passe ebenfalls auf, dass Du den Projektnamen umbenennen musst, in meinem Beispiel hieß das Projekt &#8222;WpfCommandsVbTutorial&#8220;.</p>



<h3 class="wp-block-heading">Datenkontext (DataContext) setzen</h3>



<p>Im ersten Schritt ergänzen wir die folgenden zwei Punkte in den XAML-Code des MainWindows (MainViews).</p>



<p>1. Wir mappen via &#8222;xmlns:&lt;name&gt;&#8220; einen Namespace anhand eines Aliases:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- ganz oben, im Abschnitt des Window-Tags -->
xmlns:vm="clr-namespace:WpfCommandsVbTutorial.ViewModels"</pre>



<p>2. Wir geben dem jeweiligen View einen Datenkontext (DataContext-Eigenschaft des Windows) über XAML. Wie Du vielleicht weißt, wäre dies auch via &#8222;Code behind&#8220;-Datei möglich, ich habe mich hier für die XAML Variante entschieden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- im "Content" des Windows -->
&lt;Window.DataContext>
    &lt;vm:MainViewModel />
&lt;/Window.DataContext></pre>



<p>Du kannst an dieser Stelle übrigens die Styling-relevanten Dinge ignorieren, also praktisch alles, was in &#8222;StackPanel.Resources&#8220; z. B. steht. Dies ist nur zur Anschauung erstellt worden und Du solltest Deinen Fokus größtenteils auf die oben aufgelisteten Steuerelemente legen.</p>



<p class="info-banner"><strong>&#x1f4a1;</strong> Hinweis: Wir werden im weiteren Verlauf noch an der PasswordBox und Co. arbeiten, sowie wichtige Sicherheitsaspekte besprechen. Dies hier ist daher noch nicht die finale Variante! Ebenso fehlt hier auch noch ein wichtiger Punkt bei der Benutzer-Textbox!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- in C#, there's a project prefix before Views -->
&lt;Window x:Class="Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfCommandsVbTutorial"
        mc:Ignorable="d"
        xmlns:vm="clr-namespace:WpfCommandsVbTutorial.ViewModels"
        Title="MainWindow" Background="DarkOrange" Height="450" Width="800" WindowStartupLocation="CenterScreen">
    
    &lt;Window.DataContext>
        &lt;vm:MainViewModel />
    &lt;/Window.DataContext>

    &lt;Grid>
        &lt;StackPanel Width="200" VerticalAlignment="Center" HorizontalAlignment="Center">
            &lt;StackPanel.Resources>
                &lt;Style TargetType="TextBlock">
                    &lt;Setter Property="Foreground" Value="WhiteSmoke" />
                    &lt;Setter Property="FontWeight" Value="SemiBold" />
                    &lt;Setter Property="FontSize" Value="16" />
                    &lt;Setter Property="Margin" Value="0 0 0 4" />
                &lt;/Style>
                &lt;Style TargetType="TextBox">
                    &lt;Setter Property="FontSize" Value="16" />
                    &lt;Setter Property="Margin" Value="0 0 0 4" />
                    &lt;Setter Property="Effect">
                        &lt;Setter.Value>
                            &lt;DropShadowEffect ShadowDepth="2" Direction="330" Color="Black" Opacity="0.5" BlurRadius="1"/>
                        &lt;/Setter.Value>
                    &lt;/Setter>
                &lt;/Style>
                &lt;Style TargetType="PasswordBox">
                    &lt;Setter Property="FontSize" Value="16" />
                    &lt;Setter Property="Margin" Value="0 0 0 8" />
                    &lt;Setter Property="Effect">
                        &lt;Setter.Value>
                            &lt;DropShadowEffect ShadowDepth="2" Direction="330" Color="Black" Opacity="0.5" BlurRadius="1"/>
                        &lt;/Setter.Value>
                    &lt;/Setter>
                &lt;/Style>
            &lt;/StackPanel.Resources>
            &lt;TextBlock Text="Benutzer" />
            &lt;TextBox Text="{Binding User}" />
            &lt;TextBlock Text="Passwort" />
            &lt;!-- die Passwordbox kann nicht so einfach gebunden werden und da dies nicht
Bestandteil dieses Beitrages ist, werde ich dies auf einen anderen Beitrag verlagern.
Konzentriere Dich bitte auf die Aspekte von WPF Commands :) -->
            &lt;PasswordBox />
            &lt;Button Command="{Binding LoginCommand}" Content="Anmelden" FontSize="16" />
        &lt;/StackPanel>
    &lt;/Grid>
&lt;/Window></pre>



<h2 class="wp-block-heading">Das ViewModel zur Oberfläche</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Das-MainViewModel-640px.png"><img loading="lazy" decoding="async" width="640" height="417" src="https://robbelroot.de/wp-content/uploads/2023/01/Das-MainViewModel-640px.png" alt="Ein ViewModel zur Oberfläche" class="wp-image-13686" title="Ein ViewModel zur Oberfläche"/></a><figcaption class="wp-element-caption">Ein ViewModel zur Oberfläche</figcaption></figure>



<p>Bevor wir mit den WPF Commands im Detail fortfahren können, müssen wir noch etwas bauen, was Diese letztendlich beinhaltet. Hierbei rede ich natürlich von einer ViewModel-Klasse, Welche alles Notwendige für die Datenbindungen bereitstellt. Neben dem oben im XAML erwähnten &#8222;LoginCommand&#8220;, bezieht sich dies natürlich auch auf die Eigenschaften wie &#8222;User&#8220; und &#8222;Password&#8220;.</p>



<p>Wenn wir dies auslassen würden, könnte die grafische Oberfläche Ihre dort empfangenen Änderungen nie via Datenbindungen an die dahinter liegenden ViewModel-Eigenschaften weitergeben. Somit hätten wir auch in unserer Geschäftslogik (innerhalb des ViewModels) nie die Chance, damit tatsächlich arbeiten zu können. Wie Du Dir also vorstellen kannst, wäre eine Anmeldung ohne z. B. typische Benutzer- und Passwort-Kombination ziemlich schwierig.</p>



<h3 class="wp-block-heading">Fehlermeldungen bei fehlender / falscher Datenbindung</h3>



<p>Falls Du an dieser Stelle also eine der typischen Binding-Fehlermeldungen bekommen solltest, kannst Du Dir nun vorstellen woran das liegt. Du hast vermutlich vergessen, den DataContext mit einer passenden ViewModel-Instanz zu befüllen – wie wir es im gleich folgenden Schritt tätigen werden. Typische Fehlermeldung sehen ungefähr so aus, also hier wurde z. B. die &#8222;User&#8220;-Eigenschaft nicht auf der &#8222;MainViewModel&#8220;-Instanz gefunden:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/BindingExpression-Fehler-–-User-konnte-nicht-fuer-die-Datenbindung-auf-dem-ViewModel-gefunden-werden.png"><img loading="lazy" decoding="async" width="856" height="75" src="https://robbelroot.de/wp-content/uploads/2023/01/BindingExpression-Fehler-–-User-konnte-nicht-fuer-die-Datenbindung-auf-dem-ViewModel-gefunden-werden.png" alt="BindingExpression Fehler – User konnte nicht für die Datenbindung auf dem ViewModel gefunden werden" class="wp-image-13762" title="BindingExpression Fehler – User konnte nicht für die Datenbindung auf dem ViewModel gefunden werden"/></a><figcaption class="wp-element-caption">BindingExpression Fehler – User konnte nicht für die Datenbindung auf dem ViewModel gefunden werden</figcaption></figure>



<p>Falls Du also eine derartige Fehlermeldung bekommst, stelle sicher, dass die Eigenschaft &#8222;User&#8220; in Deinem  Viewmodel existiert. Es kann hier aber auch vorkommen, dass z. B. gar kein Fehler kommt und dennoch nichts passiert. Dies ist z. B. der Fall, wenn Du vergisst, den DataContext überhaupt zu setzen! Denke daran, dass wir das hier im View selbst, also via XAML-Code weiter oben getan haben!</p>



<h3 class="wp-block-heading">Das (erste) MainViewModel erstellen</h3>



<p>Erstelle für die weitere Vorgehensweise in Richtung WPF Commands nun einmal bitte eine Klasse namens &#8222;MainViewModel&#8220; in Deinem &#8222;ViewModels&#8220;-Ordner. Unsere ViewModel-Klasse wird hierbei von der &#8222;PropertyChangedBase&#8220;-Basisklasse erben, damit wir die dort zurechtgeschriebene Funktionalität weiterverwenden können. Somit sparen wir es uns, die &#8222;INotifyPropertyChanged&#8220;-Schnittstelle immer und immer wieder manuell implementieren zu müssen. Kopiere Dir die Basisklasse ruhig von <strong><a href="https://robbelroot.de/blog/der-ultimative-inotifypropertychanged-guide/#PropertyChangedBase-Klasse" target="_blank" rel="noreferrer noopener">diesem Beitrag hier</a></strong>.</p>



<p>Nun das MainViewModel, wundere Dich bitte nicht, dass dort schon anderer Kram drin steht, aber ich möchte Dir diesen Batzen gleich nicht noch 3x um die Ohren hauen. Wir nehmen dies daher als Basis und arbeiten uns von dort aus weiter durch den Code. Es fehlen hier auch noch die ein odere andere Funktion, sowie eine Klasse für die Commands, Welche wir natürlich noch erstellen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="main-view-model">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        Private _user As String

        Public Property User As String
            Get
                Return _user
            End Get
            Set(value As String)
                If _user = value Then
                    Return
                End If
                _user = value
                NotifyOfPropertyChange()
            End Set
        End Property

        Private _password As String

        Public Property Password As String
            Get
                Return _password
            End Get
            Set(value As String)
                If _password = value Then
                    Return
                End If
                _password = value
                NotifyOfPropertyChange()
            End Set
        End Property

        Public Property LoginCommand As LoginCommand

        Sub New()
            LoginCommand = New LoginCommand()
        End Sub

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="main-view-model">using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{
    private string _user;

    public string User
    {
        get => _user;
        set
        {
            if (_user == value)
                return;
            _user = value;
            NotifyOfPropertyChange();
        }
    }

    private string _password;

    public string Password
    {
        get => _password;
        set
        {
            if (_password == value)
                return;
            _password = value;
            NotifyOfPropertyChange();
        }
    }

    public LoginCommand LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new LoginCommand();
    }

}</pre>



<h3 class="wp-block-heading">Die üblichen Mechanismen</h3>



<p>Zuerst einmal siehst Du im obigen MainViewModel-Code die 3 wichtigsten Eigenschaften für unser Login-Fenster:</p>



<ol class="wp-block-list">
<li>Die User-Eigenschaft</li>



<li>Die Password-Eigenschaft</li>



<li>Die LoginCommand-Eigenschaft</li>
</ol>



<p>Bis auf das &#8222;LoginCommand&#8220; sind alle Eigenschaften sogenannte &#8222;voll implementierte&#8220;-Eigenschaften, Sie haben also einen von uns manuell implementierten Getter und Setter. Dies geschieht deshalb, weil wir im Setter sagen müssen: &#8222;Hey, es hat sich Code-seitig z. B. der User geändert&#8220;. Das passiert einerseits, wenn wir einen gespeicherten Zugang von der Festplatten laden, aber auch, wenn der Benutzer des Programms eine Eingabe in der Textbox macht – besonders hierzu aber gleich noch etwas! Andererseits können wir dem Command das dann auch noch explizit mitteilen, denn warum sollte man sich anmelden können, wenn, wenn z. B. gar kein Benutzername eingegeben wurde? Dazu kommen wir aber noch..</p>



<p>Etwas anders sieht es wie schon gesagt beim &#8222;LoginCommand&#8220; aus, denn Dieses wird nach der Instanziierung nicht mehr geändert. Hier reicht also eine sogenannte automatisch implementierte Eigenschaft aus.</p>



<h2 class="wp-block-heading">Der erste Command-Versuch</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Cmmand-nach-3-Klicks-sperren.gif"><img loading="lazy" decoding="async" width="796" height="452" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Cmmand-nach-3-Klicks-sperren.gif" alt="WPF Command nach 3 Klicks sperren" class="wp-image-13848" title="WPF Command nach 3 Klicks sperren"/></a><figcaption class="wp-element-caption">WPF Command nach 3 Klicks sperren</figcaption></figure>



<p>An dieser Stelle werden wir den ersten Versuch Richtung eigener WPF Commands starten. Wir werden dafür das sogenannte &#8222;ICommand&#8220;-Interface (manuell) implementieren – später vereinfacht, keine Sorge! Erstelle also nun bitte eine weitere Klasse (ohne Datei) namens &#8222;LoginCmd&#8220;, Diese kannst Du für den Anfang einfach innerhalb des Wurzelverzeichnisses Deines Projektes ablegen. Dies werden wir selbstverständlich später ändern, brauchen wir aber am Anfang zur reinen Demonstration.</p>



<p>Schreibe für VB.NET anschließend – wie für Schnittstellen-Implementierungen üblich – einfach &#8222;Implements INotifyPropertyChanged&#8220; unter die beginnende Klassendefinition: &#8222;Public Class LoginCommand&#8220;. Für C# kannst Du ein &#8222;: INotifyPropertyChanged&#8220; hinter den Klassennamen schreiben. In beiden Fällen kannst Du dann die Imports durch die Visual Studio-Hilfe durchführen. Alternativ kannst Du auch Strg+&#8220;.&#8220; drücken und die dann erscheinenden Vorschläge durchführen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCmd.vb" data-enlighter-group="erstes-command-1">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' restlicher MainViewModel-Code

        Public Property LoginCommand As LoginCommand

        Sub New()
            LoginCommand = New LoginCommand()
        End Sub

        Public Class LoginCmd
            Implements ICommand

            Public Sub Execute(parameter As Object) Implements ICommand.Execute
                Throw New NotImplementedException()
            End Sub

            Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
                Throw New NotImplementedException()
            End Function

            Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

        End Class

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCmd.cs" data-enlighter-group="erstes-command-1">using System.Windows.Input;
using System;
using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restlicher MainViewModel-Code

    public LoginCmd LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new LoginCmd();
    }

    public class LoginCmd : ICommand
    {

        public void Execute(object? parameter)
        {
            throw new NotImplementedException();
        }

        public bool CanExecute(object? parameter)
        {
            throw new NotImplementedException();
        }

        public event EventHandler? CanExecuteChanged;

    }
}</pre>



<h3 class="wp-block-heading">Was soll bei Ausführung des WPF Commands passieren?</h3>



<p>Um dem Command sagen zu können: &#8222;Hey, wenn Du ausgeführt wirst, soll xy passieren&#8220;, müssen wir nun eine bestimmte Methode implementieren. Dabei handelt es sich um die &#8222;Execute&#8220;-Methode, der &#8222;ICommand&#8220;-Schnittstelle. Dort drin können wir beispielsweise einmal einen Anmeldevorgang simulieren, mehr wird denke ich zu kompliziert sein, also etwa mit Services zu kommunizieren, usw. Das werde ich aber mit Sicherheit noch in einem anderen Beitrag vertiefen!</p>



<p>Die &#8222;Execute&#8220;-Methode sieht dann grundsätzlich erstmal wie folgt aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.vb" data-enlighter-group="login-command-klasse">Public Class LoginCommand
    Implements ICommand

    Public Sub Execute(parameter As Object) Implements ICommand.Execute
        ' hier kommt rein, was beim Klick passieren soll
        Debug.WriteLine("Melde mich an")
    End Sub

    ' restlicher Code..

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.cs" data-enlighter-group="login-command-klasse">public class LoginCommand : ICommand
{

    public void Execute(object? parameter)
    {
        // hier kommt rein, was beim Klick passieren soll
        Debug.WriteLine("Melde mich an");
    }

    // restlicher Code..

}</pre>



<h3 class="wp-block-heading">Kann das WPF Command überhaupt ausgeführt werden?</h3>



<p>Nachdem wir die eine &#8222;Execute&#8220;-Methode implementiert und somit beschrieben haben, was beim Ausführen des Commands passieren soll, geht&#8217;s nun mit dem &#8222;kann ich das ausführen&#8220; weiter. Es wäre ja z. B. blöd, wenn der Benutzer der Software den &#8222;Anmelden&#8220;-Knopf spammen könnte. Stattdessen sollte man den Button deaktivieren, während z. B. eine Art Sperre stattfindet. Dazu müssen wir eine Funktion namens &#8222;CanExecute&#8220; implementieren, Welche – wie der Name schon sagt – bestimmt, ob das jeweilige Command gerade ausgeführt werden kann.</p>



<p>Der Code dazu könnte wie folgt aussehen, also, dass z. B. das Command nach 3 fehlerhaften Login-Versuchen gesperrt ist.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.vb" data-enlighter-group="gesperrtes-command">Public Class LoginCommand
    Implements ICommand

    Private _failedAttempts As Integer

    Public Sub Execute(parameter As Object) Implements ICommand.Execute
        ' simulate failed login attempt
        _failedAttempts += 1
    End Sub

    Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
        Return _failedAttempts &lt; 3
    End Function

    Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.cs" data-enlighter-group="gesperrtes-command">using System;
using System.Windows.Input;

public class LoginCommand : ICommand
{
    private int _failedAttempts;

    public void Execute(object? parameter)
    {
        // simulate failed login attempt
        _failedAttempts++;
    }

    public bool CanExecute(object? parameter)
    {
        return _failedAttempts &lt; 3;
    }

    public event EventHandler? CanExecuteChanged;

}</pre>



<p>Zum Schluss bleibt hier nun noch ein letztes Problem: Das Command wird so gesehen niemals &#8222;aktualisiert&#8220;. Es wird aktuell leider nicht nach außen bekanntgemacht: &#8222;Hey, grafische Oberfläche, evaluiere bitte einmal neu, ob ich ausgeführt werden kann, denn hier hat sich was geändert!&#8220;. Somit bleibt das Command aktuell immer ausführbar. Wenn Du stattdessen z. B. initial ein Kriterium hättest – wie z. B. eine Rolle an Nutzern– die den Button nicht drücken dürfen, dann könnte es auch sein, dass der Button permanent grau hinterlegt ist. Keine Sorge, darum kümmern wir uns nun im letzten Schritt!</p>



<h3 class="wp-block-heading">Neu evaluieren, ob ausgeführt werden kann</h3>



<p>Um der grafischen Oberfläche genau dieses Signal a la &#8222;Hey, re-evaluiere hier bitte einmal die CanExecute-Funktion&#8220; zu geben, müssen wir nur eins tun: Das Ereignis auslösen, Welches bewusst von der &#8222;ICommand&#8220;-Schnittstelle dafür vorgegeben wurde, namens &#8222;CanExecuteChanged&#8220;. Aktuell ist dies noch relativ einfach, da wir alles was wir dafür benötigen, innerhalb der Command-Instanz selbst haben.</p>



<p>Was ich meine, ist die Anzahl an fehlgeschlagenen Anmelde-Versuchen, Welche wir in der Zeile 3 deklariert haben. Wir müssten also eigentlich immer das &#8222;CanExecuteChanged&#8220;-Ereignis auslösen, wenn sich diese Variable ändert. Gleich kommen wir auch noch dazu, wie wir unter Umständen agieren könnten, wenn wir z. B. auf eine &#8222;IsLoading&#8220;-Eigenschaft eines ViewModels keinen Zugriff haben.</p>



<p>Das könnte z. B. so aussehen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.vb" data-enlighter-group="can-execute-changed-1">Public Class LoginCommand
    Implements ICommand

    Private _failedAttempts As Integer

    Public Sub Execute(parameter As Object) Implements ICommand.Execute
        ' simulate failed login attempt
        _failedAttempts += 1
        RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
    End Sub

    Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
        Return _failedAttempts &lt; 3
    End Function

    Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="LoginCommand.cs" data-enlighter-group="can-execute-changed-1">using System.Windows.Input;
using System;

public class LoginCommand : ICommand
{
    private int _failedAttempts;

    public void Execute(object? parameter)
    {
        // simulate failed login attempt
        _failedAttempts++;
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public bool CanExecute(object? parameter)
    {
        return _failedAttempts &lt; 3;
    }

    public event EventHandler? CanExecuteChanged;

}</pre>



<h3 class="wp-block-heading">Der ganze Aufwand für ein einziges Command?</h3>



<p>Ich gebe zu, dass dies alles, vor allem als Anfänger natürlich erstmal überwältigend klingen kann, besonders für bisher ein einziges Command, aber keine Sorge – &#8222;I got you&#8220;. Statt diesen Aufwand immer wieder von vorn zu betreiben, werden wir uns – als &#8222;faule&#8220; Entwickler – selbstverständlich einige Hilfsmittel schreiben, Welche uns die Arbeit vereinfachen. Im ersten Schritt wird das die gleich folgende, wiederverwendbare Klasse Namens z. B. &#8222;DelegateCommand&#8220; sein.</p>



<h2 class="wp-block-heading" id="wiederverwendbare-klasse">Eine wiederverwendbare DelegateCommand-Klasse</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2023/01/Das-DelegateCommand-–-unsere-Basisklasse-fuer-WPF-Commands-640px.png"><img loading="lazy" decoding="async" width="640" height="424" src="https://robbelroot.de/wp-content/uploads/2023/01/Das-DelegateCommand-–-unsere-Basisklasse-fuer-WPF-Commands-640px.png" alt="Das DelegateCommand – unsere Basisklasse für WPF Commands" class="wp-image-13853" title="Das DelegateCommand – unsere Basisklasse für WPF Commands"/></a><figcaption class="wp-element-caption">Das DelegateCommand – unsere Basisklasse für WPF Commands</figcaption></figure>



<p>Wie Du vermutlich im letzten Schritt festgestellt hast, ist das Ganze mit den WPF Commands nicht so &#8222;mal eben&#8220; wie mit den Click-Handlern erledigt. Lasse Dich aber bitte hier dennoch nicht dazu verführen – typisch Mensch, typisch Gewohnheitstier – dennoch wieder die alten &#8222;Button1_Click&#8220; und Co. Dinger zu verwenden. Wir können uns wie hier drüber erwähnt, auch viele Hilfsmittel erschaffen, mit Denen wir uns das Handling deutlich vereinfachen können.</p>



<p>Im Endeffekt ändert sich von der Konzeption des Commands selbst, nicht viel, wir brauchen immer noch folgende Aspekte:</p>



<ol class="wp-block-list">
<li>Was soll bei Ausführung getan werden?</li>



<li>Kann es ausgeführt werden?</li>



<li>Wann ändert sich die Info, ob&#8217;s ausgeführt werden kann?</li>
</ol>



<p>Allerdings möchten wir nun nicht jedes Mal dafür eine eigene Klasse erstellen, sondern alles ein wenig mehr zentralisieren. Das können wir ganz einfach, indem wir Obiges logisch betrachten: Punkt 1 ist einfach nur ein &#8222;Packen&#8220; Arbeit, Welchen wir in die Zukunft delegieren (vielleicht rückt der Begriff &#8222;DelegateCommand&#8220; nun etwas näher &#x1f609;), nämlich bei z. B. einem Klick. Punkt 2 ist praktisch das Gleiche in bunt, nur, dass wir eine &#8222;Ja/Nein&#8220;-Info zurückbekommen: Also einen Boolean. Punkt 3 kann je nach Fall komplizierter werden, aber auch das lässt sich regeln.</p>



<h3 class="wp-block-heading">Methoden / Funktionalität dynamisch übergeben</h3>



<p>Wenn man nun zu den obigen Erkenntnissen gekommen ist, fragt man sich im nächsten Schritt das Offensichtliche: &#8222;Okay, aber wie verlagere / gruppiere ich denn überhaupt Arbeit?&#8220;. Das Stichwort, bzw. die Stichworte Deiner Begierde nennen sich &#8222;<strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.action-1?view=net-7.0" target="_blank" rel="noreferrer noopener">Action</a></strong>&#8222;, bzw. &#8222;<strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.func-2?view=net-7.0" target="_blank" rel="noreferrer noopener">Func</a></strong>&#8222;. Diese übernehmen exakt das, was wir bruachen, Sie kapseln / gruppieren unsere Anweisungen und machen Diese praktisch ansprech- und ausführbar – auch später.</p>



<h3 class="wp-block-heading">Der erste Versuch – delegierte Arbeit</h3>



<p>Schreiben wir also nun unseren aus den Erkenntnissen resultierenden, ersten Versuch. Hierbei geht es erstmal nur darum, die &#8222;Was soll getan werden&#8220;-Anweisungen als Gruppe von Anweisungen zu verlagern / zu delegieren. Das geht auch im Endeffekt ganz einfach, schaue Dir dazu diese neue Variante unserer Command-Implementierung an.</p>



<p>Wir lassen hierbei der instaziierenden Partei die Möglichkeit, den gruppierten Stapel an Arbeit von außen mitzugeben. Beachte auch, dass wir sogar die Möglichkeit haben, einen Parameter mitzuliefern. Dadurch sind wir – indem wir z. B. eine weitere Klasse erstellen – auch nicht auf einen Übergabeparameter limitiert, könnten also praktisch eine ganze &#8222;Config&#8220; mitliefern. Natürlich muss dies passend in der Execute-Methode gecastet werden..</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.vb" data-enlighter-group="delegate-command-mit-aktion">Namespace Utils

    Public Class DelegateCommand
        Implements ICommand

        Private _action As Action(Of Object)

        Sub New(action As Action(Of Object))
            _action = action
        End Sub

        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            ' führt unsere von außen mitgegebene Aktion aus und übergibt auch den Parameter
            _action(parameter)
        End Sub

        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            Return True
        End Function

        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.cs" data-enlighter-group="delegate-command-mit-aktion">using System.Windows.Input;
using System;

namespace Utils;

public class DelegateCommand : ICommand
{
    private Action&lt;object?> _action;

    public DelegateCommand(Action&lt;object?> action)
    {
        _action = action;
    }

    public void Execute(object? parameter)
    {
        // führt unsere von außen mitgegebene Aktion aus und übergibt auch den Parameter
        _action?.Invoke(parameter);
    }

    public bool CanExecute(object? parameter)
    {
        return true;
    }

    public event EventHandler? CanExecuteChanged;

}</pre>



<h3 class="wp-block-heading">Delegierte Arbeit im MainViewModel verwenden</h3>



<p>Zurück in unserem (komprimierten) MainViewModel, könnte die Erstellung des Commands nun wie gleich folgend und vollkommen dynamisch aussehen. Beachte auch, dass wir durch Polymorphie oben ein &#8222;ICommand&#8220; deklarieren, aber ein diese Schnittstelle implementierendes Objekt zuweisen können (im Konstruktor).</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="mainvm-beispiel-mit-action-command">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' restliche Eigenschaften..

        Public Property LoginCommand As ICommand

        Sub New()
            LoginCommand = New DelegateCommand(AddressOf Login)
        End Sub

        ' unsere gruppierten Anweisungen - zusammengefasst
        Private Sub Login(parameter As Object)
            ' tu dies
            ' tu jenes
            ' tu das
        End Sub

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="mainvm-beispiel-mit-action-command">using System.Windows.Input;
using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restliche Eigenschaften..

    public ICommand LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new DelegateCommand(Login);
    }

    // unsere gruppierten Anweisungen - zusammengefasst
    private void Login(object? parameter)
    {
        // tu dies
        // tu jenes
        // tu das
    }
}</pre>



<h3 class="wp-block-heading">Was fehlt ist, ob&#8217;s geht!</h3>



<p>Was nun noch als vorletzter Punkt fehlt, ist eine dynamische Feststellung, ob das Command überhaupt ausgeführt werden kann, denn das haben wir aktuell völlig vernachlässigt. Zum Glück können wir uns auch hier ganz schnell helfen, denn dafür gab es neben der &#8222;Action&#8220; auch etwas namens &#8222;Func&#8220;. Damit können wir eine Funktion dynamisch übergeben und dessen Rückgabewert nach unserem Belieben auswerten.</p>



<p>Hierzu habe ich einen neuen Konstruktor erstellt, Welcher uns dann die optionale Möglichkeit bietet, sagen zu können: &#8222;Hey, so stellst Du fest, ob das Command ausgeführt werden kann&#8220;. Wenn dies also nicht mitgegeben wird, könnte man praktisch davon ausgehen, dass das Command immer ausgeführt werden kann.</p>



<h3 class="wp-block-heading" id="finale-delcommand-basisklasse">Die finale DelegateCommand-Basisklasse</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.vb" data-enlighter-group="delegate-command-mit-aktion2">Namespace Utils

    Public Class DelegateCommand
        Implements ICommand

        Private _action As Action(Of Object)

        Private _canExecute As Func(Of Object, Boolean)

        Sub New(action As Action(Of Object))
            _action = action
        End Sub

        Sub New(action As Action(Of Object), canExecute As Func(Of Object, Boolean))
            _action = action
            _canExecute = canExecute
        End Sub

        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            ' führt unsere von außen mitgegebene Aktion aus und übergibt auch den Parameter
            _action(parameter)
        End Sub

        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            If _canExecute Is Nothing Then
                Return True
            End If
            Return _canExecute(parameter)
        End Function

        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.cs" data-enlighter-group="delegate-command-mit-aktion2">using System.Windows.Input;
using System;

namespace Utils
{
    public class DelegateCommand : ICommand
    {
        private Action&lt;object?> _action;

        private Func&lt;object?, bool>? _canExecute;

        public DelegateCommand(Action&lt;object?> action)
        {
            _action = action;
        }

        public DelegateCommand(Action&lt;object?> action, Func&lt;object?, bool> canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public void Execute(object? parameter)
        {
            _action(parameter);
        }

        public bool CanExecute(object? parameter)
        {
            if (_canExecute == null)
                return true;
            return _canExecute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }

        public event EventHandler? CanExecuteChanged;
    }
}</pre>



<p>Nun kann unser MainViewModel wie folgt ergänzt werden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="mainvm-beispiel-mit-func-command">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' other properties..

        Private Property LoginAttempts As Integer

        Public Property LoginCommand As ICommand

        Sub New()
            LoginCommand = New DelegateCommand(AddressOf Login, AddressOf CanLogin)
        End Sub

        ' our grouped instructions - summed up
        Private Sub Login(parameter As Object)
            ' do this
            ' do that
            ' do something else
            LoginAttempts += 1
        End Sub

        Private Function CanLogin(parameter As Object) As Boolean
            ' determine, if the login process should be executed and return it
            Return LoginAttempts &lt; 3
        End Function

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="mainvm-beispiel-mit-func-command">using System.Windows.Input;
using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restliche Eigenschaften..

    private int LoginAttempts { get; set; }

    public ICommand LoginCommand { get; set; }

    public MainViewModel()
    {
        LoginCommand = new DelegateCommand(Login, CanLogin);
    }
    
    // our grouped instructions - summed up
    private void Login(object? parameter)
    {
        // do this
        // do that
        // do something else
        LoginAttempts++;
    }

    private bool CanLogin(object? parameter)
    {
        // determine, if the login process should be executed and return it
        return LoginAttempts &lt; 3;
    }
}</pre>



<h3 class="wp-block-heading">Und was, wenn es sich ändert?</h3>



<p>Nun kommen wir (sorry, endlich) zum finalen Punkt: Wir müssen auch hier die Möglichkeit bieten, sagen zu können: &#8222;Hey Oberfläche, bitte neu evaluieren, ob das Command ausgeführt werden kann&#8220;. Dafür gibt es z. B. die <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.input.commandmanager.invalidaterequerysuggested?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">&#8222;CommandManager.InvalidateRequerySuggested&#8220;-Methode</a></strong>, Welche ich aber nicht ganz toll finde. Alle Commands re-evaluieren, nur weil sich ggf. Eines geändert hat? Nee..</p>



<p>Wir werden stattdessen unser eigenes kleines Helferlein dafür einbauen, ich meine, dafür haben wir ja sowieso schon unsere Basisklasse. Wir ergänzen also eine Methode, Welche es uns von außen erlaubt, das &#8222;CanExecuteChanged&#8220;-Ereignis des Commands auszulösen. Für mich fühlt sich auch das nicht ganz super an, aber es deckt genau unsere Bedürfnisse:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.vb" data-enlighter-group="finales-delegate-command">Namespace Utils

    Public Class DelegateCommand
        Implements ICommand

        Private _action As Action(Of Object)

        Private _canExecute As Func(Of Object, Boolean)

        Sub New(action As Action(Of Object))
            _action = action
        End Sub

        Sub New(action As Action(Of Object), canExecute As Func(Of Object, Boolean))
            _action = action
            _canExecute = canExecute
        End Sub

        Public Sub Execute(parameter As Object) Implements ICommand.Execute
            _action(parameter)
        End Sub

        Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
            If _canExecute Is Nothing Then
                Return True
            End If
            Return _canExecute(parameter)
        End Function

        Public Sub RaiseCanExecuteChanged()
            RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
        End Sub

        Public Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DelegateCommand.cs" data-enlighter-group="finales-delegate-command">using System.Windows.Input;
using System;

namespace Utils;

public class DelegateCommand : ICommand
{
    private Action&lt;object?> _action;

    private Func&lt;object?, bool>? _canExecute;

    public DelegateCommand(Action&lt;object?> action)
    {
        _action = action;
    }

    public DelegateCommand(Action&lt;object?> action, Func&lt;object?, bool>? canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public void Execute(object? parameter)
    {
        _action(parameter);
    }

    public bool CanExecute(object? parameter)
    {
        if (_canExecute == null)
            return true;
        return _canExecute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public event EventHandler? CanExecuteChanged;
}</pre>



<p>Zum Schluss nun unsere letzte MainViewModel-Anpassung (bezogen auf die fehlgeschlagene Logins Geschichte):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.vb" data-enlighter-group="final-main-vm">Imports WpfCommandsVbTutorial.Utils

Namespace ViewModels

    Public Class MainViewModel
        Inherits PropertyChangedBase

        ' restliche Eigenschaften

        Public Property LoginCommand As CommandBase

        Private _loginAttempts As Integer

        Private Property LoginAttempts As Integer
            Get
                Return _loginAttempts
            End Get
            Set(value As Integer)
                _loginAttempts = value
                LoginCommand.RaiseCanExecuteChanged()
            End Set
        End Property

        Sub New()
            LoginCommand = New CommandBase(AddressOf Login, AddressOf CanLogin)
        End Sub

        Private Sub Login(parameter As Object)
            ' fehlgeschlagenen Login simulieren..
            LoginAttempts += 1
        End Sub

        Private Function CanLogin(parameter As Object) As Boolean
            Return _loginAttempts &lt; 3
        End Function

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="MainViewModel.cs" data-enlighter-group="final-main-vm">using Utils;

namespace ViewModels;

public class MainViewModel : PropertyChangedBase
{

    // restliche Eigenschaften

    public DelegateCommand LoginCommand { get; set; }

    private int _loginAttempts;

    private int LoginAttempts
    {
        get => _loginAttempts;
        set
        {
            _loginAttempts = value;
            LoginCommand.RaiseCanExecuteChanged();
        }
    }

    public MainViewModel()
    {
        LoginCommand = new DelegateCommand(Login, CanLogin);
    }

    private void Login(object? parameter)
    {
        // simulate failed login
        LoginAttempts++;
    }

    private bool CanLogin(object? parameter)
    {
        return _loginAttempts &lt; 3;
    }
}</pre>



<h2 class="wp-block-heading">Wie übergibt man Command-Parameter?</h2>



<figure class="wp-block-image size-full is-resized"><a href="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Command-Parameter-uebergeben_640px.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2023/01/WPF-Command-Parameter-uebergeben_640px.png" alt="WPF Command-Parameter übergeben" class="wp-image-14032" style="width:640px;height:360px" title="WPF Command-Parameter übergeben"/></a><figcaption class="wp-element-caption">WPF Command-Parameter übergeben</figcaption></figure>



<p>Bisher konnten wir schon viele Eindrücke in das WPF Command gewinnen, eine Sache ist jedoch noch ein wenig auf der Strecke geblieben, sorry. Es geht um das Übergeben von Parametern, da wir ja auch z. B. extra eine &#8222;Action&#8220; / &#8222;Func&#8220; mit generischem Typenparameter vom Typ &#8222;Object&#8220; deklariert haben. Bisher verwenden wir diese Möglichkeit der Parameterübergabe noch nicht.</p>



<p class="info-banner"><strong>&#x1f4a1;</strong> Hinweis: Viele Online-Code-Schnipsel verwenden die Übergabe des Parameters auch als Möglichkeit, die PasswordBox in das Command zu übergeben und so das Passwort bei Bedarf abzurufen. Es ist laut Diskussion im Netz zwar in erster Linie &#8222;sicherer&#8220; und sicherlich eine mögliche Herangehensweise, allerdings finde ich dies wenig praktikabel.</p>



<p>Jeder (und ich meine jeder) Entwickler muss hier selbst entscheiden, Welche Sicherheitsmaßnahmen für sich, Kunden und Co. angemessen sind! Dies soll die &#8222;Considerations&#8220; selbstverständlich trotzdem nicht kleinreden und man sollte sich an &#8222;best practices&#8220; halten..</p>



<h3 class="wp-block-heading">Warum, bzw. wann übergibt man Command-Parameter?</h3>



<p>Bevor man sich allerdings tiefer in diesen Dschungel wagt, macht diese kleine Überlegung ggf. auch Sinn: &#8222;Wann braucht man Command-Parameter überhaupt!?&#8220;. Grundsätzlich können wir ja auf die Eigenschaften unseres Viewmodels zugreifen, wenn wir lokale Methoden des ViewModels mit der DelegateCommand-Klasse von oben verwenden. Das stimmt soweit auch, aber wie wir schon im Absatz hier drüber gesehen haben, kann es Situationen geben, wo wir auf die Dinge ggf. keinen Zugriff haben, dann könnte so eine Übergabe helfen.</p>



<h3 class="wp-block-heading">Parameter manuell via XAML übergeben</h3>



<p>Lasse uns daher einmal im nächsten Schritt schauen, wie wir diese Möglichkeit der Parameter nun allgemein verwenden könnten. Ich denke hier zuerst an die einfachste Variante, also eine einfache &#8222;manuelle&#8220; Übergabe. Dies können wir sehr einfach im XAML-Code erledigen, indem wir einfach einen passenden Wert, an die &#8222;CommandParameter&#8220;-Eigenschaft mitliefern:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Button Command="{Binding LoginCommand}" CommandParameter="D" /></pre>



<h3 class="wp-block-heading">WPF Command-Parameter via DataBinding übergeben</h3>



<p>Auch ganz interessant ist die eigentlich offensichtlichste Sache, also die Übergabe via normalem Databinding. Hierzu kann ich einfach eine normale &#8222;Binding-Expression&#8220;, also einen Bindungs-Ausdruck schreiben. Dieser wird dann zu passender Zeit evaluiert und als CommandParameter übergeben:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;Button Command="{Binding LoginCommand}" CommandParameter="{Binding SomeBoundPropertyToPassIn}" /></pre>



<h3 class="wp-block-heading">Mehrere Parameter via Klasse oder MultiBinding übergeben</h3>



<p>Hier kommt noch ein wichtiger Punkt, da viele Anfänger daran scheitern. Häufig stellt man folgende Überlegung an: &#8222;Okay, so übergebe ich einen einzigen Parameter an das WPF Command, aber wie kann ich Mehrere auf einmal übergeben?&#8220;.</p>



<p>Aber keine Sorge, die Antwort ist relativ einfach, die erste Variante wäre via eigener Klasse. Lege dazu einfach eine passende Klasse mit den Eigenschaften / Werten, die Du übertragen möchtest, an:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="parameter-params-class">Public Class SpecialCmdParams

    Public Property SomePropToPassOne As String

    Public Property SomePropToPassTwo As Integer

    ' ...

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="parameter-params-class">public class SpecialCmdParams
{

    public string SomePropToPassOne { get; set; }

    public int SomePropToPassTwo { get; set; }

    // ...

}</pre>



<p>Instanziiere diese Klasse nun an passender Stelle, z. B. im ViewModel-Konstruktor und befülle die Eigenschaften durch passende Bindungen an z. B. Textboxen, whatever. Im nächsten Schritt kannst Du die Instanz der Klasse natürlich einfach via Datebindung (wie hier drüber, siehe &#8222;SomeBoundPropertyToPassIn&#8220;) übergeben. Gleich schauen wir uns noch an, wie man dies dann abrufen kann.</p>



<h3 class="wp-block-heading">Parameter via Multibinding übergeben</h3>



<p>Wer keine Lust hat jedes Mal eine passende Klasse zu erstellen, kann sich die Übergabe mehrerer Command-Parameter auch durch ein sogenanntes &#8222;<strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.data.multibinding?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">Multibinding</a></strong>&#8220; vereinfachen. Wie der Name schon sagt, bindet man hier nicht an ein &#8222;Ding&#8220;, sondern kann gleich mehrere Datenbindungen quasi in Einer verwenden.</p>



<p>Das Blöde ist hier nur, dass man einen &#8222;Converter&#8220; benötigt, wie soll sonst aus &#8222;mehrere Dinger&#8220; -&gt; &#8222;ein Ding&#8220; werden? Man muss hier auch noch bedenken, dass man eventuell den Weg zurück braucht, also aus einem Ding wieder Mehrere zu machen. Ein derartiges, passendes Muster finden wir bei der <strong><a href="https://learn.microsoft.com/de-de/dotnet/api/system.windows.data.imultivalueconverter?view=windowsdesktop-7.0" target="_blank" rel="noreferrer noopener">&#8222;IMultiValueConverter&#8220;-Schnittstelle</a></strong>.</p>



<p>Implementieren wir dieses Interface also einmal beispielhaft, um mehrere Zahlen zu übergeben (auch wenn dies bei einem Login keinen Sinn macht), es geht wie gesagt um &#8222;Commands&#8220; selbst :)! Wir übergeben hier einfach mal stumpf die Größe des Login-Fensters. Dies könnten wir natürlich auch durch eine normale Datenbindung realisieren, aber es geht wie gesagt um ein Beispiel!</p>



<p>Beachte, dass die Implementierung hier nur beispielhaft und z. B. nicht konfigurierbar ist. Zum Thema &#8222;ValueConverter&#8220; im Allgemeinen werde ich ggf. noch einen separaten Beitrag schreiben. Erstelle also nun einmal folgende Klasse, im (z. B.) &#8222;Utils&#8220;-Ordner</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DoubleNumberConverter.vb" data-enlighter-group="double-number-converter">Imports System.Globalization

Namespace Utils

    Public Class DoubleNumberConverter
        Implements IMultiValueConverter

        Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IMultiValueConverter.Convert
            Return String.Join("|", values)
        End Function

        Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
            Return value.ToString.Split("|")
        End Function

    End Class

End Namespace</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="DoubleNumberConverter.cs" data-enlighter-group="double-number-converter">using System.Globalization;

namespace Utils
{
    public class DoubleNumberConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            return string.Join("|", values);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            return value.ToString().Split("|");
        }
    }
}</pre>



<p>Damit können wir dann ein Multibinding realisieren, Welches dann über übliche Binding-Ausdrücke Daten mitliefert – aber eben Mehrere! Vergiss hier jedoch nicht, eine Instanz des &#8222;DoubleNumberConverters&#8220; entweder in der App.xaml / Application.xaml, oder in Deinem jeweiligen Control (UserControl, Window, etc..) zu erstellen. Ansonsten kannst Du den Konverter nicht verwenden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;!-- The Window here is named "MyWindow" for example purposes -->

    &lt;!-- further above -->
    &lt;Window.Resources>
        &lt;ResourceDictionary>
            &lt;u:DoubleNumberConverter x:Key="MyDoubleNumberConverter" />
        &lt;/ResourceDictionary>
    &lt;/Window.Resources>

&lt;!-- usage -->
&lt;Button Command="{Binding LoginCommand">
    &lt;Button.CommandParameter>
        &lt;MultiBinding Converter="{StaticResource MyDoubleNumberConverter}">
             &lt;Binding Path="ActualWidth" ElementName="MyWindow"/>
             &lt;Binding Path="ActualHeight" ElementName="MyWindow"/>
        &lt;/MultiBinding>
    &lt;/Button.CommandParameter>
&lt;/Button></pre>



<h3 class="wp-block-heading">Übergebene Parameter abgreifen</h3>



<p>Nachdem wir die Beispiele zum Übergeben der Parameter gesehen haben, schauen wir uns nun an, wie wir Diese auch wieder abgreifen können. Je nachdem Welches der obigen Beispiele Du verwendest, sieht die Vorgehensweise eigentlich immer gleich aus (auch bei CanExecute):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="getting-params">' rest of the ViewModel-Class (like MainViewModel)

' the "parameter" contains everything, but combined in one thing
Public Sub Login(parameter As Object)
    ' if it looked like this in the XAML:
    ' CommandParameter="D"
    Dim passedLetter = Convert.ToString(parameter)
    ' now there's the letter D inside passedLetter

    '' if it was a custom class
    Dim yourParam = CType(parameter, SpecialCmdParams)

    '' if it was the DoubleNumberConverter - you now have :
    Dim numbersAsStrings = Convert.ToString(parameter).Split("|")
    ' do conversion, whatever
End Sub

' rest of the ViewModel-Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="getting-params">public void Login(object parameter)
{
    // if it looked like this in the XAML:
    // CommandParameter="D"
    var passedLetter = Convert.ToString(parameter);
    // now there's the letter D inside passedLetter

    // // if it was a custom class
    var yourParam = (SpecialCmdParams)parameter;

    // // if it was the DoubleNumberConverter - you now have :
    var numbersAsStrings = Convert.ToString(parameter).Split("|");
}</pre>



<h2 class="wp-block-heading" id="downloads">Downloads</h2>



<p>Lade Dir hier gerne das Beispielprojekt (oder einzelne Bestandteile) in der Sprache Deiner Wahl herunter, da der Beitrag natürlich anhand des Themas ein wenig riesig ist. So kannst Du Dich spielerisch an die einzelnen Punkte wagen und begleitend mit dem Beitrag arbeiten. Die einzelnen Dinge beinhalten jeweils die Dateien für beide Sprachen.</p>



<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/datei-download/?dlid=5867f9d0-4c87-4691-b5af-edcfc9cf21e5" target="_blank" rel="noreferrer noopener">WpfCommandsExampleVbTutorial.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=b7a9ff1d-36a0-4517-b7c9-7d3b08395f3a" target="_blank" rel="noreferrer noopener">WpfCommandsExampleCsTutorial.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=6f4780e5-cac9-4a61-a0ef-336fdf663bfa" target="_blank" rel="noreferrer noopener">DelegateCommand.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://robbelroot.de/datei-download/?dlid=9c9ac493-82cc-45f2-a2cd-34a1dbe8e78b" target="_blank" rel="noreferrer noopener">PropertyChangedBase.zip</a></div>
</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/">Eigene WPF Commands in MVVM VB.NET &#038; C# &#8211; der 2024 Guide</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/eigene-wpf-commands-in-mvvm-vbnet-und-csharp-der-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VB NET MouseClick simulieren – mit AutoIt3</title>
		<link>https://robbelroot.de/blog/vb-net-mouseclick-simulieren-mit-autoit3/</link>
					<comments>https://robbelroot.de/blog/vb-net-mouseclick-simulieren-mit-autoit3/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sat, 02 Oct 2021 18:14:30 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[ausführen]]></category>
		<category><![CDATA[autoit]]></category>
		<category><![CDATA[autoit3]]></category>
		<category><![CDATA[autoklick]]></category>
		<category><![CDATA[autoklicker]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[automatisch]]></category>
		<category><![CDATA[automatisieren]]></category>
		<category><![CDATA[basic]]></category>
		<category><![CDATA[click]]></category>
		<category><![CDATA[klick]]></category>
		<category><![CDATA[klicken]]></category>
		<category><![CDATA[mausklick]]></category>
		<category><![CDATA[mouseclick]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[simulate]]></category>
		<category><![CDATA[simulieren]]></category>
		<category><![CDATA[steuern]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[visual]]></category>
		<category><![CDATA[visual basic]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=6393</guid>

					<description><![CDATA[<p>VB NET MouseClick simulieren Einen VB NET MouseClick simulieren zu können wollte vermutlich jeder Entwickler schon einmal. Ich würde sogar sagen, jeder Gamer sowieso, denn wer hat schon Lust auf die typische &#8222;Monkey-Work&#8220;. Zig tausend mal die gleichen Dialoge in exakter Reihenfolge zu bestätigen und sich mühselig manuell durchzuklicken. Also &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vb-net-mouseclick-simulieren-mit-autoit3/">VB NET MouseClick simulieren – mit AutoIt3</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/10/VB.NET-MouseClick-simulieren.png"><img loading="lazy" decoding="async" width="1200" height="675" src="https://robbelroot.de/wp-content/uploads/2021/10/VB.NET-MouseClick-simulieren.png" alt="VB.NET MouseClick simulieren" class="wp-image-6395" title="VB.NET MouseClick simulieren"/></a><figcaption>VB.NET MouseClick simulieren</figcaption></figure>






<h2 class="wp-block-heading">VB NET MouseClick simulieren</h2>



<p>Einen <strong>VB NET MouseClick simulieren</strong> zu können wollte vermutlich jeder Entwickler schon einmal.</p>



<p>Ich <strong>würde </strong>sogar <strong>sagen</strong>, <strong>jeder Gamer </strong>sowieso, denn wer hat schon Lust auf die typische &#8222;Monkey-Work&#8220;.</p>



<p><strong>Zig tausend mal </strong>die <strong>gleichen Dialoge </strong>in exakter Reihenfolge zu <strong>bestätigen </strong>und sich <strong>mühselig </strong>manuell <strong>durchzuklicken</strong>.</p>



<p>Also echt mal, da hat doch <strong>keiner Bock drauf</strong>, seufz, jedenfalls aller spätestens beim 2, 3, .. Mal.</p>



<p><strong>Natürlich </strong>treffen wir <strong>ähnliche Bedürfnisse </strong>und <strong>Probleme </strong>auch <strong>im Büroalltag </strong>an, Excel, usw. lassen lieb grüßen.</p>



<p><strong>Ein Glück</strong>, dass man (angehender) <strong>Entwickler </strong>ist, gell &#x1f609;!</p>



<h2 class="wp-block-heading">Auf YouTube ansehen –  VB NET MouseClick simulieren</h2>



<iframe loading="lazy" width="560" height="315" src="https://www.youtube-nocookie.com/embed/wlG_qTQF7fk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>



<p class="margin-after-video-block"><strong>Falls </strong>Du <strong>eher </strong>für eine <strong>visuelle Darstellung </strong>des Beitrages zu haben bist, <strong>kannst </strong>Du Dir <strong>natürlich auch </strong>das <strong>Video </strong>(vielleicht auch ergänzend zum Beitrag) <strong>anschauen</strong>.</p>



<p><strong>Bei </strong>meinen Beiträgen bringe ich gerne auch immer diverse Detail-Infos, oder andere Dinge hinein.</p>



<p><strong>Leider fehlt </strong>mir dazu oft <strong>in </strong>den <strong>Videos die Zeit</strong>, da ich denke, dass man einen <strong>Beitrag einfacher durchscrollen </strong>kann.</p>



<p>Vor allem den Beitrag sinnvoll zu gliedern ist denke ich einfacher, <strong>als durch </strong>ein <strong>Video </strong>zu <strong>zappen</strong>.</p>



<p><strong>Immerhin hat <a href="https://youtube.com" target="_blank" rel="noreferrer noopener">YouTube</a></strong> seit geraumer Zeit <strong>eine </strong>Art <strong>Kapitelübersicht </strong>hinzugefügt, Welche ich auch gern verwende.</p>



<style>
.margin-after-video-block {
  margin-top: 1em;
}
</style>



<h2 class="wp-block-heading">Die Idee zum Beitrag – VB NET MouseClick</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/BackgroundWorker-starten.jpg"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/09/BackgroundWorker-starten.jpg" alt="VB NET MouseClick - Die Idee zum Beitrag" class="wp-image-5991" title="VB NET MouseClick - Die Idee zum Beitrag"/></a><figcaption>VB NET MouseClick &#8211; Die Idee zum Beitrag</figcaption></figure>



<p><strong>Man möchte sich </strong>im Optimalfall natürlich <strong>selbst helfen </strong>können und <strong>besonders </strong>auch <strong>zukunftsorientiert</strong>.</p>



<p><strong>Gerne hätte man </strong>eine Art <strong>Hilfe </strong>in Form einer Person, der man dann einfach sagen könnte &#8222;<strong>Mach </strong>das <strong>mal</strong>..&#8220;.</p>



<p><strong>Als Programmierer können wir </strong>uns kreativen Köpfen selbstverständlich <strong>selbst </strong>unter die Arme greifen, man weiß nur nicht immer wie.</p>



<p><strong>Daher lass</strong>&#8218; <strong>mich Dir </strong>mit diesem kleinen Beitrag <strong>helfen </strong>und zeigen, wie Du einen <strong>VB NET MouseClick</strong> mit der Hilfe von <strong><a href="https://www.autoitscript.com/site/" target="_blank" rel="noreferrer noopener">AutoIt3</a></strong> durchführen kannst.</p>



<p><strong>Dadurch kannst Du </strong>dann verschiedene Tools wie <strong>diverse Klicker</strong>&#8211;<strong>Bots </strong>realisieren und Dir Deinen <strong>Alltag erleichtern</strong>.</p>



<h2 class="wp-block-heading">Nicht ohne mein AutoIt</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/10/VB.NET-ImageSearch-mit-Hilfe-von-AutoIt.png"><img loading="lazy" decoding="async" width="1200" height="675" src="https://robbelroot.de/wp-content/uploads/2021/10/VB.NET-ImageSearch-mit-Hilfe-von-AutoIt.png" alt="Mit Hilfe von AutoIt" class="wp-image-6341" title="Mit Hilfe von AutoIt"/></a><figcaption>Mit Hilfe von AutoIt</figcaption></figure>



<p>Naja <strong>etwas witzig angelehnt </strong>die Headline hier, <strong>aber tatsächlich </strong>werden wir dieses kleine Geplänkel <strong>nicht ohne AutoIt3 </strong>realisieren.</p>



<p><strong>Klar gibt </strong>es auch die <strong>Möglichkeit </strong>in VB NET <strong>einfach </strong>ich nenne es mal &#8222;<strong>manuell</strong>&#8220; einen <strong>Mausklick </strong>zu <strong>simulieren</strong>, aber ich find&#8217;s hier <strong>mit AutoIt3 </strong>definitiv <strong>angenehmer</strong>.</p>



<p><strong>Wie auch </strong>im <a href="https://robbelroot.de/blog/vb-net-imagesearch-bilder-in-spielen-desktop-und-co-suchen/" target="_blank" rel="noreferrer noopener"><strong>&#8222;ImageSearch&#8220;-Beitrag</strong></a> schon angesprochen gehen <strong>viele Entwickler kritisch mit </strong>der <strong>Speichergröße </strong>der Projekte um.</p>



<p>Das <strong>kann ich </strong>natürlich <strong>nachvollziehen</strong>, da ich <strong>selbst </strong>ein <strong>Freund des Minimalismus </strong>bin, <strong>jedoch </strong>kann man die <strong>Kirche </strong>auch <strong>im Dorf lassen</strong>.</p>



<p>Ich würde mit Sicherheit in <strong>Festplatten</strong>&#8211;<strong>Generation </strong>&#8222;<strong>Terrabyte zum Preis von damaligen 80GB</strong>&#8220; nicht anfangen für 1MB rumzunörgeln.</p>



<p><strong>Letztendlich </strong>muss man ja <strong>immer </strong>den möglichen <strong>Mehrwert in Relation zur Eigenarbeit</strong> sehen.</p>



<p><strong>Später </strong>kannst Du <strong>bei </strong>einem intelligent <strong>strukturierten Programm natürlich </strong>bedürftige <strong>Komponenten </strong>isoliert <strong>austauschen</strong>.</p>



<h2 class="wp-block-heading">Projekt in Visual Studio vorbereiten</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/10/Neues-Visual-Studio-Projekt-anlegen.png"><img loading="lazy" decoding="async" width="640" height="380" src="https://robbelroot.de/wp-content/uploads/2021/10/Neues-Visual-Studio-Projekt-anlegen.png" alt="Neues Visual Studio Projekt anlegen und vorbereiten" class="wp-image-6352" title="Neues Visual Studio Projekt anlegen und vorbereiten"/></a><figcaption>Neues Visual Studio Projekt anlegen und vorbereiten</figcaption></figure>



<p><strong>Lade </strong>Dir <strong>jetzt </strong>die <strong><a href="/downloads/tools/AutoItPackage.zip" target="_blank" rel="noreferrer noopener">benötigten Bibliotheken</a></strong> direkt hier <strong>herunter</strong>, oder suche alternativ nach <strong>anderen Quellen</strong> im Netz.</p>



<p><strong>Danach </strong>kannst Du wie üblich ein <strong>neues </strong>Windows Forms-, oder auch ein WPF-<strong>Projekt anlegen</strong>.</p>



<p><strong>Lege </strong>die &#8222;<strong>AutoItX3.Assembly.dll</strong>&#8222;-Datei nun als Verweis an, <strong>damit </strong>dein Projekt <strong>damit arbeiten </strong>kann.</p>



<p>Ganz <strong>einfach </strong>geht das zum Beispiel rechts <strong>über </strong>den <strong>Projektmappen-Explorer</strong> in Visual Studio.</p>



<p><strong>Führe </strong>dazu einfach einen <strong>rechten Mausklick </strong>auf &#8222;<strong>Verweise</strong>/<strong>Abhängigkeiten</strong>&#8220; <strong>aus </strong>und wähle die Datei aus.</p>



<p><strong>Neben </strong>dem Weg über den <strong>Projektmappen</strong>&#8211;<strong>Explorer </strong>gibt es <strong>auch </strong>noch <strong>andere Möglichkeiten</strong>.</p>



<p><strong>Kopiere </strong>anschließend <strong>alle anderen </strong>Dateien (außer die ImageSearchDLL.dll) <strong>in </strong>den <strong>Debug-Ordner</strong> deines Projekts.</p>



<p>Die <strong>oben </strong>erwähnte <strong>Datei </strong>dürfte sich <strong>aufgrund </strong>des <strong>Imports schon </strong>im Ordner befinden.</p>



<h2 class="wp-block-heading">Nun zum Code – VB NET MouseClick</h2>



<p>Sehen wir uns <strong>im nächsten Schritt </strong>den benötigten <strong>Code </strong>im Detail an.</p>



<p><strong>Wenn </strong>Du alle <strong>vorherigen Schritte abgeschlossen </strong>hast, kannst Du <strong>nun </strong>den korrekten <strong>Import </strong>durchführen:</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 AutoIt</pre>



<p><strong>Damit </strong>wird <strong>im aktuellen Scope </strong>die &#8222;AutoItX&#8220;-<strong>Klasse verfügbar</strong>, womit wir im nächsten Part den Klick realisieren können.</p>



<p><strong>Zuvor </strong>kannst Du Dir allerdings <strong>noch </strong>eine <strong>solche </strong>(oder ähnliche) <strong>GUI zurechtklicken </strong>– relativ simpel.</p>



<p><strong>Füge </strong>einfach nur <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.label?view=net-5.0" target="_blank" rel="noreferrer noopener">2 Labels</a></strong>, <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.textbox?view=net-5.0" target="_blank" rel="noreferrer noopener">2 Textboxen</a></strong> und einen <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.button?view=net-5.0" target="_blank" rel="noreferrer noopener">Button</a> </strong>hinzu:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/10/VB.NET-MouseClick-simulieren-Beispiel-GUI.png"><img loading="lazy" decoding="async" width="296" height="147" src="https://robbelroot.de/wp-content/uploads/2021/10/VB.NET-MouseClick-simulieren-Beispiel-GUI.png" alt="VB.NET MouseClick simulieren Beispiel-GUI" class="wp-image-6431" title="VB.NET MouseClick simulieren Beispiel-GUI"/></a><figcaption>VB.NET MouseClick simulieren Beispiel-GUI</figcaption></figure>



<p>Die <strong>2 Labels</strong> sollen <strong>einfach </strong>nur ein wenig <strong>fürs Auge </strong>klar machen, <strong>welche Inputs</strong>, <strong>wo hinein </strong>müssen.</p>



<p><strong>Bei </strong>den <strong>Textboxen </strong>handelt es sich um <strong>Eingabefelder für </strong>die <strong>Koordinaten</strong>, allerdings verzichten wir hier im Code auf Prüfungen.</p>



<p><strong>Wir werden </strong>also <strong>der Einfachheit halber nicht </strong>weiter <strong>überprüfen</strong>, <strong>ob </strong>es sich bei den Eingaben um <strong>Zahlen </strong>handelt, bzw. <strong>ob </strong>etwas <strong>eingegeben </strong>wurde.</p>



<p><strong>Nun ziehen </strong>wir die <strong>Koordinaten aus </strong>den <strong>Textboxen </strong>und wandeln Diese dann in <strong>Ganzzahlen </strong>vom Typ <strong><a href="https://docs.microsoft.com/de-de/dotnet/visual-basic/language-reference/data-types/integer-data-type" target="_blank" rel="noreferrer noopener">Integer</a></strong> um:</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 x = Integer.Parse(tbX.Text)
Dim y = Integer.Parse(tbY.Text)</pre>



<p><strong>Danach </strong>können wir dann die wichtige und <strong>essentielle AutoIt3-Funktion</strong> namens &#8222;<strong>MouseClick</strong>&#8220; 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="">AutoItX.MouseClick("LEFT", x, y, 1, 50)</pre>



<h3 class="wp-block-heading">MouseClick-Parameter</h3>



<p>Die <strong>möglichen Parameter </strong>möchte ich <strong>hier </strong>einmal näher erläutern:</p>



<p><strong>Weitere Informationen </strong>findest Du <strong>in </strong>der <strong><a href="https://www.autoitscript.com/autoit3/docs/functions/MouseClick.htm" target="_blank" rel="noreferrer noopener">offiziellen Dokumentation</a></strong> von AutoIt.</p>



<h4 class="wp-block-heading">button As String</h4>



<p><strong>Hier </strong>können wir den <strong>gewünschten Button als String </strong>übergeben, mögliche Werte sind: &#8222;&#8220; (leer), &#8222;LEFT&#8220;, &#8222;MIDDLE&#8220;, &#8222;RIGHT&#8220;, &#8222;PRIMARY&#8220;, &#8222;MAIN&#8220;, &#8222;SECONDARY&#8220;, &#8222;MENU&#8220;. <strong>Wenn </strong>ein <strong>leerer String </strong>übergeben wird, wird <strong>automatisch </strong>die <strong>linke Maustaste </strong>verwendet.</p>



<h4 class="wp-block-heading">x As Integer</h4>



<p>Gibt den Koordinaten-Punkt des Klicks auf der horizontalen (X) Achse an.</p>



<h4 class="wp-block-heading">y As Integer</h4>



<p>Setzt die Koordinate des auszuführenden Klicks auf der vertikalen (Y) Achse.</p>



<h4 class="wp-block-heading">numClicks As Integer</h4>



<p><strong>Legt </strong>die <strong>Anzahl der </strong>durchzuführenden <strong>Klicks </strong>an den Koordinaten <strong>fest</strong>.</p>



<h4 class="wp-block-heading">speed As Integer</h4>



<p>Gibt die Geschwindigkeit der durchzuführenden Klicks an.</p>



<h2 class="wp-block-heading">Der komplette Code – TL;DR</h2>



<p>Es ist <strong>zwar nicht viel</strong>, oder gar komplexer Code, <strong>aber hier </strong>siehst Du Ihn <strong>in einem</strong> <strong>Stück </strong>– vielleicht für die &#8222;TL;DR&#8220;-guys haha.</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 AutoIt

Public Class Form1

    Private Sub btnExecuteClick_Click(sender As Object, e As EventArgs) Handles btnExecuteClick.Click
        Dim x = Integer.Parse(tbX.Text)
        Dim y = Integer.Parse(tbY.Text)
        AutoItX.MouseClick("LEFT", x, y, 1, 50)
    End Sub

End Class</pre>



<h2 class="wp-block-heading">Weiterführende Links</h2>



<ul class="wp-block-list"><li><strong><a href="https://robbelroot.de/blog/vb-net-imagesearch-bilder-in-spielen-desktop-und-co-suchen" target="_blank" rel="noreferrer noopener">VB NET ImageSearch – Bilder in Spielen, Desktop und Co. suchen</a></strong></li><li><strong><a href="https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert" target="_blank" rel="noreferrer noopener">VB NET Web API &#8211; Währungskurs Service Konsum von Grund auf erklärt</a></strong></li><li><strong><a href="https://robbelroot.de/blog/vbnet-texterkennung-auf-bildern/" target="_blank" rel="noreferrer noopener">VB.NET Texterkennung auf Bildern via Google Cloud Vision API [OCR]</a></strong></li></ul>



<h2 class="wp-block-heading">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" href="/downloads/tools/AutoItPackage.zip" target="_blank" rel="noreferrer noopener">AutoItPackage.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link" href="/downloads/vbnet/MouseClickExample.zip" target="_blank" rel="noreferrer noopener">MouseClickExample.zip</a></div>
</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vb-net-mouseclick-simulieren-mit-autoit3/">VB NET MouseClick simulieren – mit AutoIt3</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vb-net-mouseclick-simulieren-mit-autoit3/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET Button Beispiel</title>
		<link>https://robbelroot.de/blog/vbnet-button-beispiel/</link>
					<comments>https://robbelroot.de/blog/vbnet-button-beispiel/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Tue, 29 Jun 2021 19:12:57 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET lernen]]></category>
		<category><![CDATA[beispiel]]></category>
		<category><![CDATA[button]]></category>
		<category><![CDATA[click]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[ereignis]]></category>
		<category><![CDATA[handler]]></category>
		<category><![CDATA[klick]]></category>
		<category><![CDATA[knopf]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=2489</guid>

					<description><![CDATA[<p>VB.NET Button Beispiel In meinem VB.NET Button Beispiel lernst Du alles Wichtige über das Button-Steuerelement. Falls Du mit dem Button in VB.NET schon Deine ersten Erfahrung gemacht hast, könnte der Beitrag über die manuelle Auslösung des Click-Events für Dich von Interesse sein. Der Button, wohl eines der wichtigsten Steuerelemente in &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-button-beispiel/">VB.NET Button Beispiel</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel.png"><img loading="lazy" decoding="async" width="1024" height="536" src="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel-1024x536.png" alt="VB.NET Button Beispiel" class="wp-image-2491" title="VB.NET Button Beispiel" srcset="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel-1024x536.png 1024w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel-300x157.png 300w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel-768x402.png 768w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel-700x366.png 700w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel-332x174.png 332w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>VB.NET Button Beispiel</figcaption></figure>






<h2 class="wp-block-heading">VB.NET Button Beispiel</h2>



<p>In meinem <strong>VB.NET Button Beispiel</strong> <strong>lernst </strong>Du alles <strong>Wichtige über </strong>das <strong>Button</strong>-Steuerelement.</p>



<p><strong>Falls </strong>Du mit dem <strong>Button in VB.NET</strong> schon Deine <strong>ersten Erfahrung</strong> gemacht hast, könnte der <strong><a href="/blog/vbnet-button-click-ausloesen" target="_blank" rel="noreferrer noopener">Beitrag über die manuelle Auslösung des Click-Events</a></strong> für Dich von Interesse sein.</p>



<p>Der <strong>Button</strong>, wohl <strong>eines </strong>der <strong>wichtigsten Steuerelemente</strong> in der Welt der Programmierung – so auch <strong>in VB.NET</strong>.</p>



<h2 class="wp-block-heading">Los geht&#8217;s</h2>



<p><strong>Ziehe </strong>um loszulegen ein <strong>Button</strong>-Steuerelement <strong>aus </strong>der <strong>Toolbox auf </strong>die <strong>Form</strong>.</p>



<p><strong>Alternativ </strong>kannst Du den <strong>Button in </strong>der <strong>Toolbox </strong>auch <strong>doppelklicken</strong>.</p>



<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel.gif"><img loading="lazy" decoding="async" width="440" height="283" src="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Beispiel.gif" alt="VB.NET Button auf die Form ziehen" class="wp-image-2552" title="VB.NET Button auf die Form ziehen"/></a><figcaption>VB.NET Button auf die Form ziehen</figcaption></figure>



<p><strong>Sobald </strong>sich der <strong>Button auf </strong>der <strong>Form </strong>befindet, <strong>können </strong>wir mit dem <strong>Styling beginnen</strong> – falls gewünscht natürlich!</p>



<h2 class="wp-block-heading">Eigenschaften – VB.NET Button Beispiel</h2>



<p>Im <strong>folgenden Teil</strong> gehe ich näher <strong>auf </strong>die einzelnen <strong>Eigenschaften </strong>der <strong>Kategorie nach</strong> ein.</p>



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



<h4 class="wp-block-heading">Name</h4>



<p><strong>Sicherlich eine </strong>der <strong>wichtigsten Eigenschaften </strong>aller Controls.</p>



<p>Sie <strong>bestimmt wie </strong>wir das jeweilige <strong>Control im Code</strong> <strong>ansprechen </strong>und <strong>kann </strong>natürlich einerseits als <strong>Orientierungshilfe und </strong>andererseits als <strong>prägnante Beschreibung</strong> dienen.</p>



<p><strong>Nachdem </strong>Du ein <strong>Control auf </strong>die <strong>Form </strong>gezogen hast, sollte <strong>Dein erster Schritt</strong> immer sein, dem <strong>Control </strong>einen <strong>passenden Namen</strong> zu <strong>geben</strong>.</p>



<h4 class="wp-block-heading">Enabled</h4>



<p>Bestimmt, <strong>ob </strong>das Steuerelement <strong>aktiviert </strong>ist.</p>



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



<p>Schauen wir uns nun einmal <strong>die </strong>– <strong>wichtigsten </strong>– <strong>Styling </strong>bezogenen <strong>Eigenschaften </strong>des Buttons an. </p>



<h4 class="wp-block-heading">Anchor</h4>



<p>Wie bei jedem Steuerelement, Welches von der <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.control?view=net-5.0" target="_blank" rel="noreferrer noopener">Basisklasse Control</a></strong> erbt, können wir auch hier <strong>die Ausrichtung des Buttons bestimmen</strong>.  </p>



<h4 class="wp-block-heading">AutoSize</h4>



<p>Diese Eigenschaft <strong>hilft </strong>uns dabei, <strong>die Größe</strong> des Buttons <strong>automatisch </strong>bei Textänderung <strong>anzupassen</strong>.</p>



<p>Das <strong>kann </strong>natürlich besonders dann <strong>von Vorteil sein</strong>, <strong>wenn </strong>sich der <strong>Text </strong>des Buttons <strong>während </strong>der <strong>Laufzeit verändert</strong>.</p>



<h4 class="wp-block-heading">BackColor</h4>



<p>Mit dieser <strong>Eigenschaft </strong>können wir die <strong>Hintergrundfarbe des Buttons</strong> bestimmen.</p>



<h4 class="wp-block-heading">BackgroundImage</h4>



<p>Hier können wir ein <strong>Bild für den Hintergrund</strong> des Buttons festlegen.</p>



<h4 class="wp-block-heading">FlatAppearance</h4>



<p>In <strong>Kombination </strong>mit der <strong>FlatStyle-Eigenschaft</strong> auf Flat gesetzt, können wir hier <strong>weitere Design-Möglichkeiten</strong> erreichen.</p>



<h4 class="wp-block-heading">FlatStyle</h4>



<p><strong>Bestimmt die </strong>Art der <strong>Darstellung </strong>des Buttons. Siehe auch die FlatAppearance.</p>



<h4 class="wp-block-heading">ForeColor</h4>



<p>Legt die <strong>Schriftfarbe </strong>innerhalb des Buttons fest.</p>



<h4 class="wp-block-heading">Image</h4>



<p>Damit können wir wie in vielen Programmen üblich ein <strong>Bild für den Button festlegen</strong>.</p>



<h4 class="wp-block-heading">Size</h4>



<p>Die Size-Eigenschaft <strong>bestimmt die Größe</strong> des Buttons.</p>



<h4 class="wp-block-heading">Text</h4>



<p>Hiermit können wir den <strong>Text innerhalb des Buttons</strong> festlegen.</p>



<h4 class="wp-block-heading">Visible</h4>



<p>Damit können wir bestimmen, <strong>ob </strong>der <strong>Button sichtbar</strong> ist.</p>



<h2 class="wp-block-heading">Das Click-Ereignis – VB.NET Button Beispiel</h2>



<p>Das <strong>Haupt-Ereignis</strong> worum sich <strong>beim Button</strong> so gut wie alles dreht.</p>



<p><strong>Was passiert</strong>, <strong>wenn </strong>man <strong>auf </strong>den <strong>Button klickt</strong>, kann man mit einem passenden Ereignishandler zu diesem Ereignis <strong>festlegen</strong>.</p>



<p><strong>Wenn </strong>es schon um ein <strong>VB.NET Button Beispiel</strong> geht, <strong>dann </strong>auch um das <strong>Click-Ereignis</strong> &#x1f913;!</p>



<h3 class="wp-block-heading">Ein Beispiel-Ereignishandler</h3>



<p><strong>Hier </strong>findest Du einen <strong>Beispiel-Ereignishandler</strong>:</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 Sub btnSayHello_Click(sender As Object, e As EventArgs) Handles btnSayHello.Click
    ' write what should happen next
End Sub</pre>



<p><strong>Dort</strong> drin <strong>bestimmst Du</strong>, <strong>was passieren </strong>soll, <strong>wenn auf </strong>den <strong>Button geklickt </strong>wird, bzw. genauer genommen, <strong>wenn </strong>der <strong>Button</strong> sein <strong>Click-Ereignis auslöst</strong>.</p>



<h2 class="wp-block-heading">Code – VB.NET Button Beispiel</h2>



<p>Da es sich <strong>bei diesem Beitrag</strong> ein <strong>vor allem</strong> an <strong>Anfänger </strong>gerichtetes <strong>Beispiel </strong>handelt, beginne ich bei den <strong>kompletten Basics</strong>.</p>



<h3 class="wp-block-heading">Den Button mit Code versehen</h3>



<p><strong>Um </strong>den <strong>Button mit Code </strong>zu <strong>versehen</strong>, sprich das was passiert, <strong>wenn man </strong>darauf zum Beispiel <strong>klickt</strong>, etc. gibt es 3 gängige Möglichkeiten.</p>



<p>Die <strong>vierte </strong>und mir erstmals gerade zuletzt – &#x1f602; – einfallende <strong>Möglichkeit </strong>stelle ich im Beitrag <strong><a href="/blog/vbnet-button-zur-laufzeit-erstellen" target="_blank" rel="noreferrer noopener">VB.NET Button zur Laufzeit erstellen</a></strong> vor.</p>



<h4 class="wp-block-heading">Über Doppelklick im Designer</h4>



<p>Die <strong>vermutlich einfachste Methode</strong> für Beginner ist es, den <strong>Button im Designer doppelt anzuklicken</strong>.</p>



<p><strong>Dadurch </strong>kommen wir <strong>in </strong>das – ich nenne es immer gerne – <strong>Haupt-Event</strong> <strong>des </strong>jeweiligen <strong>Controls</strong>.</p>



<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-im-Designer-doppelklicken.gif"><img loading="lazy" decoding="async" width="440" height="283" src="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-im-Designer-doppelklicken.gif" alt="VB.NET Button im Designer doppelklicken um Klick-Ereignishandler zu generieren" class="wp-image-2567" title="VB.NET Button im Designer doppelklicken um Klick-Ereignishandler zu generieren"/></a><figcaption>VB.NET Button im Designer doppelklicken um Klick-Ereignishandler zu generieren</figcaption></figure>



<p><strong>Mit </strong>dem <strong>Doppelklick generiert </strong>uns <strong>Visual Studio automatisch</strong> einen <strong>passenden Ereignishandler </strong>in Form von einer <strong>Sub </strong>– <strong>verknüpft an </strong>das <strong>Ereignis </strong>mit dem <strong>Handles-Schlüsselwort</strong>.</p>



<h4 class="wp-block-heading">Via Dropdown im Designer</h4>



<p>Eine <strong>nächste Möglichkeit</strong> wäre die Generierung des Handlers über die <strong>Dropdowns im Designer</strong>.</p>



<p><strong>Klicke </strong>dafür den <strong>Button an</strong>, um Ihn <strong>auszuwählen </strong>und <strong>schaue </strong>anschließend <strong>rechts in die Eigenschaften</strong>.</p>



<p>Oben <strong>im Eigenschafts-Fenster</strong> siehst Du einen <strong>kleinen Blitz</strong>, <strong>klicke </strong>Ihn <strong>an </strong>und <strong>suche nach</strong> dem <strong>Click-Ereignis</strong>, mache dann einen <strong>Doppelklick in die leere Zelle</strong> daneben.</p>



<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-Event-via-Designer-Dropdown-generieren.gif"><img loading="lazy" decoding="async" width="440" height="283" src="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-Event-via-Designer-Dropdown-generieren.gif" alt="VB.NET Button Click Event via Designer Dropdown generieren" class="wp-image-2572" title="VB.NET Button Click Event via Designer Dropdown generieren"/></a><figcaption>VB.NET Button Click Event via Designer Dropdown generieren</figcaption></figure>



<h4 class="wp-block-heading">Per Dropdown in der Code-Ansicht</h4>



<p>Folgende und vorerst letzte Möglichkeit <strong>verwende ich </strong>gerne, <strong>wenn </strong>ich mich gerade <strong>sowieso in </strong>der <strong>Code-Ansicht </strong>aufhalte.</p>



<p>Gehe dazu <strong>im Designer</strong> auf die <strong>zweite ComboBox</strong>, <strong>oben in der Mitte</strong> des Bildschirms (zumindest wenn Du ein Steuerelement der aktuellen Form bearbeiten möchtest!).</p>



<p>Wähle <strong>anschließend </strong>das <strong>Ereignis </strong>aus, <strong>Welches </strong>Du <strong>mit Code versehen</strong>, bzw. <strong>wofür </strong>Du einen <strong>Ereignishandler generieren</strong> möchtest.</p>



<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-Event-via-Code-Dropdowns-generieren.gif"><img loading="lazy" decoding="async" width="650" height="198" src="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-Event-via-Code-Dropdowns-generieren.gif" alt="VB.NET Button Click Event via Code Dropdowns generieren" class="wp-image-2575" title="VB.NET Button Click Event via Code Dropdowns generieren"/></a><figcaption>VB.NET Button Click Event via Code Dropdowns generieren</figcaption></figure>



<h3 class="wp-block-heading">Handler-Code hinzufügen</h3>



<p><strong>Nun</strong>, <strong>da </strong>wir den <strong>Handler </strong>für den Button auf eine der beschriebenen Art <strong>generiert </strong>haben, <strong>können </strong>wir endlich &#8222;<strong>tatsächlichen Code</strong>&#8220; <strong>hinzufügen</strong>.</p>



<p><strong>Um</strong> weiterhin <strong>einfach</strong> <strong>zu bleiben </strong>fügen wir die Anzeige einer simple <strong>MessageBox</strong> hinzu.</p>



<h3 class="wp-block-heading">Mehr als einen Handler</h3>



<p><strong>Was </strong>vor allem <strong>viele Anfänger nicht wissen</strong> ist, <strong>dass </strong>es <strong>nicht </strong>in Stein gemeißelt ist, <strong>bei einem Handler</strong> zu bleiben.</p>



<p>Wir <strong>können dem Click-Ereignis</strong> des Buttons <strong>auch </strong>ohne Probleme <strong>mehrere Ereignishandler</strong> der gleichen Signatur – dem gleichen Aufbau der Methode – <strong>hinzufügen</strong>.</p>



<h2 class="wp-block-heading">Kompletter Code – VB.NET Button Beispiel</h2>



<p>Hier findest Du den <strong>Code zu meinem VB.NET Button Beispiel</strong>:</p>



<h3 class="wp-block-heading">Mit nur einem Ereignishandler</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 Form1
    Private Sub btnSayHello_Click(sender As Object, e As EventArgs) Handles btnSayHello.Click
        MessageBox.Show("Hallo Welt!")
    End Sub
End Class</pre>



<h3 class="wp-block-heading">Mit mehr als einem Ereignishandler</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 Form1
    Private Sub btnSayHello_Click(sender As Object, e As EventArgs) Handles btnSayHello.Click
        MessageBox.Show("Hallo Welt!")
    End Sub
    Private Sub btnSayHello2_Click(sender As Object, e As EventArgs) Handles btnSayHello.Click
        MessageBox.Show("Hallo Welt! 2")
    End Sub
End Class</pre>



<h2 class="wp-block-heading">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" href="/downloads/vbnet/ButtonExample.zip" target="_blank" rel="noreferrer noopener">Button Example</a></div>
</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-button-beispiel/">VB.NET Button Beispiel</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-button-beispiel/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>VB.NET Button Click auslösen</title>
		<link>https://robbelroot.de/blog/vbnet-button-click-ausloesen/</link>
					<comments>https://robbelroot.de/blog/vbnet-button-click-ausloesen/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Tue, 29 Jun 2021 13:09:55 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[ausführen]]></category>
		<category><![CDATA[auslösen]]></category>
		<category><![CDATA[button]]></category>
		<category><![CDATA[by code]]></category>
		<category><![CDATA[click]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[execute]]></category>
		<category><![CDATA[klick]]></category>
		<category><![CDATA[ohne click]]></category>
		<category><![CDATA[press]]></category>
		<category><![CDATA[simulate]]></category>
		<category><![CDATA[trigger]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=2467</guid>

					<description><![CDATA[<p>VB.NET Button Click auslösen In diesem Beitrag erkläre ich Dir, wie Du in VB.NET ein Button Click auslösen kannst – und zwar via Code! Falls Du noch gar nicht mit dem Button-Steuerelement gearbeitet hast, kannst Du Dir unter folgendem Link meinen allgemeinen Beitrag zum Button Beispiel anschauen. Wie Du in &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-button-click-ausloesen/">VB.NET Button Click auslösen</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen.png"><img loading="lazy" decoding="async" width="1024" height="536" src="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen-1024x536.png" alt="" class="wp-image-2469" srcset="https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen-1024x536.png 1024w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen-300x157.png 300w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen-768x402.png 768w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen-700x366.png 700w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen-332x174.png 332w, https://robbelroot.de/wp-content/uploads/2021/06/VB.NET-Button-Click-ausloesen.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>VB.NET Button Click auslösen</figcaption></figure>






<h2 class="wp-block-heading">VB.NET Button Click auslösen</h2>



<p>In <strong>diesem Beitrag</strong> erkläre ich Dir, wie Du in <strong>VB.NET ein Button Click auslösen</strong> kannst – und zwar <strong>via Code</strong>!</p>



<p><strong>Falls </strong>Du noch <strong>gar nicht mit dem Button</strong>-Steuerelement <strong>gearbeitet </strong>hast, kannst Du Dir unter folgendem Link meinen <a href="/blog/vbnet-button-beispiel" target="_blank" rel="noreferrer noopener"><strong>allgemeinen Beitrag zum Button</strong></a><strong> Beispiel</strong> anschauen.</p>



<p>Wie Du in <strong>VB.NET </strong>einen <strong><a href="/blog/vbnet-button-zur-laufzeit-erstellen" target="_blank" rel="noreferrer noopener">Button zur Laufzeit erstellst</a></strong>, <strong>kannst Du </strong>in diesem Beitrag <strong>hier lernen</strong>.</p>



<h3 class="wp-block-heading">Wir waren alle schonmal da</h3>



<p>Ich <strong>glaube jeder .NET Entwickler</strong> <strong>kam</strong> zu Beginn seiner Entwickler-Karriere <strong>irgendwann an diesen Punkt</strong>.</p>



<p>Man <strong>hat etwas</strong> Tolles <strong>in </strong>seinen <strong>Button gecoded</strong> und <strong>es lief rund</strong> und ohne <strong>Fehler</strong>.</p>



<p>Nun <strong>kommt der Punkt</strong>, an dem man <strong>diese Funktionalität</strong> – versteckter Tipp löl – nun <strong>von anderer Stelle</strong> aus <strong>aufrufen</strong> möchte.</p>



<h3 class="wp-block-heading" id="unfassbare-spielereien">Kreative Spielereien</h3>



<p><strong>Im Laufe</strong> meiner Tätigkeit <strong>als Softwareentwickler</strong> im Bereich von VB.NET <strong>habe ich</strong> schon so <strong>Einiges gesehen</strong>.</p>



<p>Ein <strong>lustiges Beispiel </strong>war ein <strong>völliger VB.NET-Anfänger </strong>– daher seid in Gedanken nicht zu hart zu Ihm –, <strong>Welcher per </strong>codeorientierter <strong>Mausbewegung, etc</strong>. einen <strong>Button anklicken </strong>wollte &#x1f602;.</p>



<p><strong>Zum Glück</strong> <strong>muss </strong>man <strong>nicht auf solche</strong> wirklich komplizierte <strong>Methoden zurückgreifen</strong>, wo kämen wir denn da hin!</p>



<h2 class="wp-block-heading">Sei gewarnt</h2>



<p><strong>Ich möchte</strong> an dieser Stelle schonmal direkt den <strong>Spoiler erwähnen</strong>, dass das, was Du&nbsp;vorhast, nicht das Gelbe <strong>vom Ei</strong> ist!</p>



<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/06/stop.jpg"><img loading="lazy" decoding="async" width="1024" height="576" src="https://robbelroot.de/wp-content/uploads/2021/06/stop-1024x576.jpg" alt="Stop Schild – Sei gewarnt" class="wp-image-1947" srcset="https://robbelroot.de/wp-content/uploads/2021/06/stop-1024x576.jpg 1024w, https://robbelroot.de/wp-content/uploads/2021/06/stop-300x169.jpg 300w, https://robbelroot.de/wp-content/uploads/2021/06/stop-768x432.jpg 768w, https://robbelroot.de/wp-content/uploads/2021/06/stop-700x393.jpg 700w, https://robbelroot.de/wp-content/uploads/2021/06/stop-332x187.jpg 332w, https://robbelroot.de/wp-content/uploads/2021/06/stop.jpg 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Sei gewarnt</figcaption></figure>



<h3 class="wp-block-heading">Schreib Dich nicht ab, lern&#8216;..</h3>



<p><strong>Ebenfalls </strong>möchte ich Dir hier aber <strong>keinen Vorwurf machen</strong>, denn Du <strong>wusstest es</strong> vermutlich einfach <strong>nicht besser</strong>, als Du danach gesucht hast.</p>



<p><strong>Ich selbst kenne </strong>diese <strong>Problematik aus </strong>meiner <strong>Anfangszeit </strong>als .NET-Entwickler!</p>



<p><strong>Selbstverständlich </strong>bin ich <strong>froh</strong>, <strong>dass </strong>Dich Deine Suche <strong>auf meine Seite</strong> und somit <strong>zu mir geführt</strong> hat &#x1f60a;.</p>



<h3 class="wp-block-heading">Meine Erfahrung – häufige Billligung  </h3>



<p><strong>Umso lustiger</strong> wird es – zumeist – <strong>nachher</strong>, wie man den <strong>Wald vor lauter Bäumen</strong> nicht <strong>sehen </strong>konnte.</p>



<p><strong>Manchmal </strong>ist es leider jedoch <strong>nicht </strong>unbedingt so <strong>lustig</strong>, vor allem, <strong>wenn </strong>gewisse <strong>Aktionen Folgen </strong>in: <strong>Wartung</strong>, <strong>Verständnis</strong> und mehr <strong>nach </strong>sich <strong>ziehen</strong>.</p>



<p>&#8222;<strong>Leider</strong>&#8220; musste <strong>ich </strong>schon oft die <strong>Erfahrung machen</strong>, dass ehemalige Nachhilfe-<strong>Schüler</strong>, <strong>Internetforen-Nutzer</strong>, jedoch auch Kunden, etc. <strong>bewusst </strong>den <strong>falschen Weg wählten</strong>.</p>



<p><strong>Oft hieß es</strong>: &#8222;Ja, ich <strong>weiß</strong>, <strong>dass </strong>das <strong>so nicht gut</strong> ist, aber das <strong>ist </strong>jetzt <strong>einfacher</strong> so!&#8220;</p>



<h2 class="wp-block-heading">Code – VB.NET Button Click auslösen</h2>



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



<p><strong>Um </strong>das <strong>Beispiel nicht </strong>zu <strong>verkomplizieren </strong>habe ich <strong>auf tiefgehendere Sachen </strong>wie die z. B. die <strong>Dependency-Injection verzichtet</strong>.</p>



<p>Das <strong>Beispiel </strong>dürfte ohnehin <strong>Aufgrund </strong>der <strong>zusätzlichen Klassen für Anfänger </strong>schon <strong>etwas schwieriger </strong>sein.</p>



<p><strong>Insgesamt hängt </strong>das natürlich <strong>vom </strong>individuellen <strong>Fortschritt in VB.NET </strong>und dem Verständnis dafür <strong>ab</strong>.</p>



<h3 class="wp-block-heading">Manueller Aufruf  der Handler-Sub – Erster Anlauf</h3>



<p>Der <strong>erste </strong>deinerseits versuchte <strong>Anlauf könnte </strong>ungefähr wie folgt, ausgesehen haben, bzw. aussehen.</p>



<p>Du <strong>versuchst </strong>die <strong>Dir bekannte Sub</strong> des Button-Click <strong>Ereignishandlers </strong>einfach <strong>händisch</strong>, also via Code <strong>aufzurufen</strong>.</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="">btnSearchBills_Click()</pre>



<p>Doch <strong>während </strong>Du die Zeile <strong>fast fertig tippst,</strong> <strong>fällt </strong>Dir vermutlich <strong>auf</strong>, <strong>dass </strong>da <strong>was fehlt </strong>&#x1f648;.</p>



<p><strong>Die Sub</strong>, <strong>die Du aufrufen wolltest</strong>, <strong>erwartet </strong>nämlich <strong>zwei Parameter</strong>, <strong>Welche </strong>Dich <strong>eventuell </strong>vor die <strong>Frage </strong>stellen: &#8222;Wo bekomme ich Diese her?&#8220;.</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="">sender As Object, e As EventArgs</pre>



<p><strong>In </strong>der <strong>Theorie </strong>ist die &#8222;<strong>Lösung</strong>&#8220; ganz <strong>einfach</strong> – zumindest, wenn man weiß wie &#x1f602;:</p>



<h4 class="wp-block-heading">sender As Object</h4>



<p>Der &#8222;<strong>sender</strong>&#8220; ist ja letztendlich <strong>nichts anderes</strong>, <strong>als </strong>das <strong>Objekt</strong>, <strong>Welches </strong>das <strong>Ereignis ausgelöst hat</strong>, worauf der Ereignishandler dann reagiert.</p>



<p><strong>Da wir</strong> ja <strong>wissen</strong>, <strong>dass </strong>der <strong>Button </strong>letztendlich das <strong>Ereignis auslösen </strong>würde, <strong>können </strong>wir <strong>Diesen </strong>ja schonmal <strong>übergeben </strong>und <strong>machen </strong>somit <strong>Signatur-technisch</strong> nichts verkehrt.</p>



<h4 class="wp-block-heading">e As EventArgs</h4>



<p>Der <strong>andere </strong>fehlende <strong>Parameter</strong>, also der <strong>Zweite</strong>, <strong>ist </strong>da etwas <strong>komplizierter</strong>, <strong>obwohl </strong>ich <strong>auch schon beim Ersten</strong> sagen kann: &#8222;<strong>Wenn </strong>Du schon <strong>beim Sender</strong> <strong>auf </strong>die <strong>Lösung gekommen </strong>bist – <strong>Respekt</strong>!&#8220;</p>



<p>Die <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.eventargs?view=net-5.0" target="_blank" rel="noreferrer noopener">EventArgs-Klasse</a></strong> bietet ein &#8222;<strong>Shared-Readonly-Feld</strong>&#8220; namens &#8222;<a href="https://docs.microsoft.com/de-de/dotnet/api/system.eventargs.empty?view=net-5.0" target="_blank" rel="noreferrer noopener"><strong>Empty</strong></a>&#8220; an.</p>



<p><strong>Wie </strong>der <strong>Name </strong>schon <strong>verrät</strong>, <strong>handelt </strong>es sich bei dem dahinterstehenden &#8222;Wert&#8220; praktisch <strong>um </strong>&#8222;<strong>leere EventArgs</strong>&#8222;, <strong>Welche </strong>wir <strong>dann mitliefern</strong> können, <strong>falls </strong>wir <strong>keine Event-Daten</strong> an sich <strong>benötigen</strong>.</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="">btnSearchBills_Click(btnSearchBills, EventArgs.Empty)</pre>



<h3 class="wp-block-heading">PerformClick – Der einfache Ansatz</h3>



<p>Im Endeffekt müssen wir es uns gar nicht so kompliziert wie oben machen.</p>



<p>Das <strong>Rumschlagen mit Parametern</strong> und das <strong>manuelle Aufrufen</strong> der Ereignishandler-Sub ist <strong>nicht notwendig</strong>, <strong>da </strong>der <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.button?view=net-5.0" target="_blank" rel="noreferrer noopener">Button</a> </strong>von Haus aus <strong>eine Möglichkeit bietet</strong>.</p>



<p>Die <strong>Methode,</strong> die wir suchen <strong>heißt</strong> *Trommelwirbel*: <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.button.performclick?view=net-5.0" target="_blank" rel="noreferrer noopener">PerformClick</a></strong>:</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="">btnSearchBills.PerformClick()</pre>



<h3 class="wp-block-heading">VB.NET Button Click auslösen – Der Richtige Ansatz</h3>



<p><strong>Im letzten</strong> und größten <strong>Abschnitt</strong> des Beitrages, kommen wir <strong>zum </strong>&#8222;<strong>richtigen</strong>&#8220; <strong>Ansatz</strong>.</p>



<p><strong>Ich halte</strong> die <strong>vorherigen Ansätze</strong> für einen <strong>schlechten Stil</strong>, bzw. <strong>für falsch</strong>, <strong>weil </strong>Sie meiner Meinung nach <strong>falsche Absichten widerspiegeln</strong>.</p>



<p><strong>Wenn man möchte</strong>, <strong>dass </strong>ein <strong>Button Click via Code ausgelöst</strong> wird, <strong>dann möchte man</strong> nicht wirklich den Button auslösen, sondern <strong>den Code</strong>, <strong>der dahinter steckt</strong>!</p>



<h4 class="wp-block-heading">Benötigte Steuerelemente</h4>



<h5 class="wp-block-heading">DataGridView</h5>



<p><strong>In </strong>dem <strong>DataGridview zeigen </strong>wir die für das Beispiel <strong>genutzten Testdaten</strong> in Form von <strong>Rechnungsdaten an</strong>.</p>



<p>2 Labels</p>



<p>Um die <strong>Textboxen </strong>optional <strong>mit Informationen </strong>zu <strong>bestücken</strong></p>



<h5 class="wp-block-heading">TextBox</h5>



<p>Eine Textbox für die <strong>Suche nach</strong> einer <strong>Rechnung via Id</strong>.</p>



<h5 class="wp-block-heading">TextBox</h5>



<p>Dann noch eine weitere Textbox für die <strong>Suche nach Rechnungen via Kunden-Name</strong>.</p>



<h5 class="wp-block-heading">Button</h5>



<p>Einen Button für den <strong>Reset der Suchfelder</strong></p>



<p>Button</p>



<p>Die <strong>Suchfunktion auszulösen </strong>wird von diesem Button gesteuert.</p>



<h4 class="wp-block-heading">Eigenschaften</h4>



<h5 class="wp-block-heading">billService</h5>



<p>Der <strong>Rechnungsservice </strong>ist – wie für Services bei <strong>Dependency Injection</strong> üblich, aber in diesem Fall nicht verwendet – eine &#8222;Private Property&#8220;.</p>



<h5 class="wp-block-heading">Bills</h5>



<p>Bei &#8222;<strong>bills</strong>&#8220; <strong>handelt </strong>es sich <strong>um die Rechnungsdaten</strong>, die wir <strong>für </strong>dieses <strong>Beispiel </strong>testweise <strong>erstellen</strong>, <strong>laden </strong>und <strong>anzeigen </strong>werden.</p>



<h4 class="wp-block-heading">Konstruktoren</h4>



<h5 class="wp-block-heading">New</h5>



<p>Wir <strong>brauchen </strong>in unserem Fall <strong>nur </strong>den <strong>Standard-Konstruktor</strong>, <strong>Welchen </strong>wir <strong>für </strong>die <strong>Vorbereitung </strong>unseres <strong>Services </strong>und z. B. dem <strong>DataGridView </strong>nutzen.</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="">Sub New()
    InitializeComponent()
    ' should be done with dependency injection like things
    ' just for displaying puporses..
    billService = New BillService()
    Bills = New List(Of Bill)
    ConfigureBillDataGrid()
End Sub</pre>



<h4 class="wp-block-heading">Methoden</h4>



<h5 class="wp-block-heading">ConfigureBillDataGrid</h5>



<p>Ich denke diese <strong>Methode </strong>ist <strong>relativ selbsterklärend</strong>.</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 Sub ConfigureBillDataGrid()
    With dgvBills
        .AllowUserToAddRows = False
        .AllowUserToDeleteRows = False
        .AllowUserToResizeRows = False
        .AllowUserToOrderColumns = False
        .AllowUserToResizeColumns = False
        .ReadOnly = True
        .SelectionMode = DataGridViewSelectionMode.FullRowSelect
        .BackgroundColor = Color.White
        .RowHeadersVisible = False
        ' columns being added in visual designer..
    End With
End Sub</pre>



<h5 class="wp-block-heading">btnSearchBills_Click</h5>



<p>Das ist die <strong>Click-Ereignishandler</strong>-Sub <strong>für </strong>den <strong>Button</strong>.</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 Sub btnSearchBills_Click(sender As Object, e As EventArgs) Handles btnSearchBills.Click
    SearchBills()
End Sub</pre>



<h5 class="wp-block-heading">SearchBills</h5>



<p>Das ist der <strong>Star des Tages</strong>, denn diese Sub ist die letztendliche <strong>Alternative zum &#8222;Button.PerformClick()&#8220;</strong>.</p>



<h5 class="wp-block-heading">ShowBillsInDataGrid</h5>



<p>Hier kommt der <strong>Code </strong>rein, der <strong>notwendig </strong>ist, <strong>um </strong>die <strong>Rechnungen anzuzeigen</strong>.</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 Sub ShowBillsInDataGrid(bills As List(Of Bill))
    ' could/should be done with BindingList which supports AddRange
    ' but thats part of another tutorial :)
    ' so this is it for now
    dgvBills.DataSource = Nothing
    Me.Bills.Clear()
    Me.Bills.AddRange(bills)
    dgvBills.DataSource = Me.Bills
End Sub</pre>



<h5 class="wp-block-heading">btnClearSearchFields_Click</h5>



<p>Das ist der <strong>Ereignishandler </strong>für das <strong>Klick-Ereignis</strong> des <strong>Reset-Buttons</strong> für die <strong>Suchfelder</strong>.</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 Sub btnClearSearchFields_Click(sender As Object, e As EventArgs) Handles btnClearSearchFields.Click
    tbBillId.Clear()
    tbBillCustomer.Clear()
    ' or
    ' tbBillCustomer.Text = ""
End Sub</pre>



<h5 class="wp-block-heading">SearchBox_KeyDown</h5>



<p>Das ist die <strong>Methode</strong>, <strong>die auf </strong>die <strong>KeyDown</strong>-Ereignisse <strong>der </strong>2 <strong>Suchfelder reagiert</strong>.</p>



<p><strong>Wenn in </strong>einem der <strong>Suchfelder </strong>die <strong>Escape-Taste</strong> <strong>gedrückt </strong>wird, nehmen wir das als Befehl dafür, <strong>dass </strong>die <strong>Felder zurückgesetzt </strong>werden sollen.</p>



<p><strong>Bei </strong>der <strong>Verwendung </strong>der <strong>Enter-Taste</strong>, lösen wir die <strong>Suche der Rechnungen</strong> erneut 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 Sub SearchBox_KeyDown(sender As Object, e As KeyEventArgs) Handles tbBillId.KeyDown, tbBillCustomer.KeyDown
    If e.KeyCode = Keys.Escape Then
       Dim theTextBox = CType(sender, TextBox)
       theTextBox.Clear()
    ElseIf e.KeyCode = Keys.Enter Then
        SearchBills()
    End If
End Sub</pre>



<h3 class="wp-block-heading">Bill-Klasse</h3>



<p>Diese Klasse <strong>spiegelt </strong>eine <strong>einzelne Rechnung </strong>wieder.</p>



<p>Die Id ist denke ich selbstredend..</p>



<p>Der <strong>Customer </strong>wurde hier <strong>bewusst als String</strong>, <strong>statt </strong>als <strong>Objekt </strong>gewählt, um das <strong>Beispiel einfacher zu halten</strong> und den <strong>Fokus nicht</strong> zu <strong>verschieben</strong>.</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 Bill

    Public Property Id As Integer

    ' should be an object but for this example, made easier
    Public Property Customer As String

    Sub New()

    End Sub

    Sub New(id As Integer)
        Me.Id = id
    End Sub

    Sub New(id As Integer, customer As String)
        Me.Id = id
        Me.Customer = customer
    End Sub

End Class</pre>



<h3 class="wp-block-heading">BillService-Klasse</h3>



<p>Diese Klasse spiegelt einen <strong>Service</strong> <strong>für </strong>die <strong>Aktionen bezüglich </strong>der <strong>Rechnungen </strong>wieder.</p>



<p><strong>Wenn </strong>eine <strong>neue Instanz</strong> der BillService-Klasse erzeugt wird, <strong>lade </strong>ich <strong>im Konstruktor</strong> deren <strong>Testdaten</strong>, <strong>ansonsten </strong>würden Diese natürlich <strong>aus</strong> einer <strong>Datenbank o. Ä.</strong> kommen.</p>



<p>Sie <strong>bietet </strong>eine <strong>Funktion an</strong>, <strong>um </strong>eine <strong>Rechnung </strong>via <strong>Id </strong>zu <strong>suchen</strong>.</p>



<p><strong>Zusätzlich </strong>gibt es eine <strong>Funktion</strong>, um <strong>Rechnungen anhand</strong> des <strong>Kundennamens </strong>zu <strong>finden</strong>.</p>



<p><strong>Um </strong>die <strong>Parameter dynamisch </strong>zu halten, habe ich ein Dictionary verwendet.</p>



<p><strong>Wenn </strong>in Diesem ein <strong>Schlüssel namens </strong>&#8222;<strong>customer</strong>&#8220; drin ist, wird der dahinter stehende Wert als <strong>Such-Name</strong> verwendet – <strong>Großschreibung nicht </strong>beachtend.</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 BillService

    Private bills As List(Of Bill)

    Sub New()
        bills = New List(Of Bill)
        MockupData()
    End Sub

    Private Sub MockupData()
        With bills
            .Add(New Bill(1, "John Doe"))
            .Add(New Bill(2, "Jane Doe"))
            .Add(New Bill(3, "Maximilian Maximum"))
            .Add(New Bill(4, "Jesus Christ"))
            .Add(New Bill(5, "Michael Jackson"))
        End With
    End Sub

    Public Function FindById(id As Integer) As Bill
        Return bills.SingleOrDefault(Function(x) x.Id = id)
        '' or the selfmade long version:
        'For Each bill In bills
        '    If bill.Id = id Then
        '        Return bill
        '    End If
        'Next
        'Return Nothing
    End Function

    Public Function FindAllBy(criteria As Dictionary(Of String, String)) As List(Of Bill)
        Dim filteredBills = New List(Of Bill)
        ' first put all in
        filteredBills.AddRange(bills)
        ' filter for example by name 
        If criteria.ContainsKey("customer") Then
            Dim customer = criteria.Item("customer").ToLower()
            filteredBills = filteredBills.Where(Function(x) x.Customer.ToLower().Contains(customer)).ToList()
        End If
        ' add more filtering..
        Return filteredBills
    End Function

End Class
</pre>



<h2 class="wp-block-heading">Der komplette Code – VB.NET Button Click auslösen</h2>



<p><strong>In </strong>diesem <strong>Abschnitt </strong>findest du den <strong>kompletten Code</strong> zum <strong>Thema</strong>: <strong>VB.NET Button Click auslösen</strong>.</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 Form1

    Private Property billService As BillService

    Public Property Bills As List(Of Bill)

    Sub New()
        InitializeComponent()
        ' should be done with dependency injection like things
        ' just for displaying puporses..
        billService = New BillService()
        Bills = New List(Of Bill)
        ConfigureBillDataGrid()
    End Sub

    Private Sub ConfigureBillDataGrid()
        With dgvBills
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .AllowUserToResizeRows = False
            .AllowUserToOrderColumns = False
            .AllowUserToResizeColumns = False
            .ReadOnly = True
            .SelectionMode = DataGridViewSelectionMode.FullRowSelect
            .BackgroundColor = Color.White
            .RowHeadersVisible = False
            ' columns being added in visual designer..
        End With
    End Sub

    Private Sub btnSearchBills_Click(sender As Object, e As EventArgs) Handles btnSearchBills.Click
        SearchBills()
    End Sub

    Private Sub SearchBills()
        Dim givenIdText = tbBillId.Text.Trim()
        Dim billId As Integer
        Dim bills As List(Of Bill) = New List(Of Bill)
        If Integer.TryParse(givenIdText, billId) Then
            Dim bill = billService.FindById(billId)
            If bill IsNot Nothing Then
                bills.Add(bill)
            End If
            ShowBillsInDataGrid(bills)
            ' OpenDetailForm() – Maybe?
            Return
        End If

        Dim searchCriteria = New Dictionary(Of String, String)

        Dim customerName = tbBillCustomer.Text.Trim()
        If Not String.IsNullOrWhiteSpace(customerName) Then
            searchCriteria.Add("customer", customerName)
        End If

        Dim searchResults = billService.FindAllBy(searchCriteria)
        bills.AddRange(searchResults)
        ShowBillsInDataGrid(bills)
    End Sub

    Private Sub ShowBillsInDataGrid(bills As List(Of Bill))
        ' could/should be done with BindingList which supports AddRange
        ' but thats part of another tutorial :)
        ' so this is it for now
        dgvBills.DataSource = Nothing
        Me.Bills.Clear()
        Me.Bills.AddRange(bills)
        dgvBills.DataSource = Me.Bills
    End Sub

    Private Sub btnClearSearchFields_Click(sender As Object, e As EventArgs) Handles btnClearSearchFields.Click
        tbBillId.Clear()
        tbBillCustomer.Clear()
        ' or
        ' tbBillCustomer.Text = ""
    End Sub

    Private Sub SearchBox_KeyDown(sender As Object, e As KeyEventArgs) Handles tbBillId.KeyDown, tbBillCustomer.KeyDown
        If e.KeyCode = Keys.Escape Then
            Dim theTextBox = CType(sender, TextBox)
            theTextBox.Clear()
        ElseIf e.KeyCode = Keys.Enter Then
            SearchBills()
        End If
    End Sub

End Class

Public Class Bill

    Public Property Id As Integer

    ' should be an object but for this example, made easier
    Public Property Customer As String

    Sub New()

    End Sub

    Sub New(id As Integer)
        Me.Id = id
    End Sub

    Sub New(id As Integer, customer As String)
        Me.Id = id
        Me.Customer = customer
    End Sub

End Class

Public Class BillService

    Private bills As List(Of Bill)

    Sub New()
        bills = New List(Of Bill)
        MockupData()
    End Sub

    Private Sub MockupData()
        With bills
            .Add(New Bill(1, "John Doe"))
            .Add(New Bill(2, "Jane Doe"))
            .Add(New Bill(3, "Maximilian Maximum"))
            .Add(New Bill(4, "Jesus Christ"))
            .Add(New Bill(5, "Michael Jackson"))
        End With
    End Sub

    Public Function FindById(id As Integer) As Bill
        Return bills.SingleOrDefault(Function(x) x.Id = id)
        '' or the selfmade long version:
        'For Each bill In bills
        '    If bill.Id = id Then
        '        Return bill
        '    End If
        'Next
        'Return Nothing
    End Function

    Public Function FindAllBy(criteria As Dictionary(Of String, String)) As List(Of Bill)
        Dim filteredBills = New List(Of Bill)
        ' first put all in
        filteredBills.AddRange(bills)
        ' filter for example by name 
        If criteria.ContainsKey("customer") Then
            Dim customer = criteria.Item("customer").ToLower()
            filteredBills = filteredBills.Where(Function(x) x.Customer.ToLower().Contains(customer)).ToList()
        End If
        ' add more filtering..
        Return filteredBills
    End Function

End Class</pre>



<h2 class="wp-block-heading">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" href="/downloads/vbnet/SimulateButtonClick.zip" target="_blank" rel="noreferrer noopener">SimulateButtonClick Example</a></div>
</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-button-click-ausloesen/">VB.NET Button Click auslösen</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-button-click-ausloesen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
