{"id":55000174,"date":"2019-04-01T00:00:00","date_gmt":"2020-03-27T19:37:13","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=174"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"EDM_Blaettern_in_Datensaetzen","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/EDM_Blaettern_in_Datensaetzen\/","title":{"rendered":"EDM: Bl&auml;ttern in Datens&auml;tzen"},"content":{"rendered":"<p><b>Wenn Sie und Ihre Kunden die Arbeit mit der Detailansicht von Access-Formularen gewohnt sind, m&ouml;chten Sie vielleicht auch in einem WPF-Fenster mit der Detailansicht der Daten einer Klasse bl&auml;ttern k&ouml;nnen. Dieser Artikel zeigt, wie Sie einem Detailformular die Daten einer Tabelle &uuml;ber die entsprechende DbSet-Auflistung zuweisen und wie Sie mit entsprechenden Schaltfl&auml;chen in den Datens&auml;tzen bl&auml;ttern k&ouml;nnen.<\/b><\/p>\n<h2>Ziel der Erweiterung<\/h2>\n<p>Welche M&ouml;glichkeiten zum Bl&auml;ttern in den Datens&auml;tzen wollen wir dem Benutzer anbieten Der Benutzer soll zum ersten, zum letzten, zum vorherigen und zum n&auml;chsten Datensatz bl&auml;ttern k&ouml;nnen. Au&szlig;erdem w&auml;re es hilfreich, wenn direkt ein neuer, leerer Datensatz angezeigt werden k&ouml;nnte. <\/p>\n<h2>Voraussetzungen<\/h2>\n<p>Wir bauen uns auf die Schnelle eine Beispielanwendung zusammen. Dazu nutzen wir die Techniken, die wir im Artikel <b>Detailformulare mit weiteren Steuerelementen <\/b>vorgestellt haben. Alternativ k&ouml;nnen Sie auch einfach das Beispielprojekt aus dem Download verwenden. Die Schritte sehen in aller K&uuml;rze wie folgt aus:<\/p>\n<ul>\n<li>Neues Projekt auf Basis der Vorlage <b>Visual Basic|Windows Desktop|WPF-App <\/b>erstellen.<\/li>\n<li>Neues Element des Typs <b>ADO.NET Entity Data Model <\/b>namens <b>BestellverwaltungContext <\/b>mit der Vorlage <b>Leeres Code First-Modell <\/b>hinzuf&uuml;gen.<\/li>\n<li>In der Access-Datenbank <b>AccessZuWPFFormulare.accdb <\/b>aus dem Download die Prozedur <b>EDMErstellen <\/b>des Moduls <b>mdlEDM <\/b>aufrufen und den entstehenden Code aus der Zwischenablage nach den Anweisungen in den Kommentaren an den entsprechenden Stellen platzieren. Hier finden sich auch die Hinweise auf die Aufrufe der Befehle Enable-Migrations, Add-Migration und Update-Database, mit denen die Datenbank erstellt und gef&uuml;llt wird.<\/li>\n<li>Den XAML-Code f&uuml;r das gew&uuml;nschte Detailformular, zum Beispiel <b>frmKundendetails<\/b>, mit dem folgenden Aufruf der Prozedur <b>FormularNachWPF <\/b>in die Zwischenablage kopieren: <b>FormularNachWPF &#8220;frmKundendetails&#8221;, &#8220;tblKunden&#8221;<\/b><\/li>\n<li>Den Inhalt der Zwischenablage in das Fenster <b>MainWindow.xaml <\/b>kopieren (oder in ein anderes, neues Fenster)<\/li>\n<li>Den VB-Code f&uuml;r die Code behind-Datei mit dem folgenden Aufruf der Prozedur <b>FormularNachWPF_CodeBehind <\/b>in die Zwischenablage kopieren: <b>FormularNachWPF_CodeBehind &#8220;frmKundendetails&#8221;, &#8220;Kunde&#8221;, &#8220;Kunden&#8221;, &#8220;BestellverwaltungContext&#8221;<\/b><\/li>\n<li>Den Inhalt der Zwischenablage in das Code behind-Modul <b>MainWindow.xaml.vb <\/b>oder das entsprechende andere Code behind-Modul kopieren.<\/li>\n<\/ul>\n<p>Das Ergebnis nach dem Start der Anwendung sieht wie in Bild 1 aus. Hier wollen wir nun die Schaltfl&auml;chen zum Bl&auml;ttern in den Datens&auml;tzen hinzuf&uuml;gen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_174_001.png\" alt=\"Fenster ohne Schaltfl&auml;chen zum Bl&auml;ttern\" width=\"424,7115\" height=\"396,6415\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Fenster ohne Schaltfl&auml;chen zum Bl&auml;ttern<\/span><\/b><\/p>\n<h2>Schaltfl&auml;chen hinzuf&uuml;gen<\/h2>\n<p>Die Schaltfl&auml;chen f&uuml;gen wir in einem Element namens <b>StackPanel <\/b>hinzu, das ein Container f&uuml;r nebeneinander oder &uuml;bereinander angeordnete Steuer-elemente ist. Dieses Element f&uuml;llen wir mit f&uuml;nf <b>Button<\/b>-Elementen, deren Code wir wie folgt erg&auml;nzen:<\/p>\n<pre>&lt;StackPanel Orientation=\"Horizontal\" HorizontalAlignment=\"Left\" Height=\"28\" Margin=\"0,273,0,0\" VerticalAlignment=\"Top\" Width=\"339\"&gt;\r\n     &lt;Button x:Name=\"btnErster\" Content=\"&lt;&lt;\" Click=\"btnErster_Click\" Width=\"25\" Margin=\"2,2,2,2\"\/&gt;\r\n     &lt;Button x:Name=\"btnVorheriger\" Content=\"&lt;\" Click=\"btnVorheriger_Click\" Width=\"25\" Margin=\"2,2,2,2\"\/&gt;\r\n     &lt;Button x:Name=\"btnNaechster\" Content=\"&gt;\" Click=\"btnNaechster_Click\" Width=\"25\" Margin=\"2,2,2,2\"\/&gt;\r\n     &lt;Button x:Name=\"btnLetzter\" Content=\"&gt;&gt;\" Click=\"btnLetzter_Click\" Width=\"25\" Margin=\"2,2,2,2\"\/&gt;\r\n     &lt;Button x:Name=\"btnNeu\" Content=\"*\" Click=\"btnNeu_Click\" Width=\"25\" Margin=\"2,2,2,2\"\/&gt;\r\n&lt;\/StackPanel&gt;<\/pre>\n<p>Dabei m&uuml;ssen die Kleiner- und Gr&ouml;&szlig;er-Zeichen im Code in der Eigenschaft <b>Content<\/b> decodiert werden, und zwar das Gr&ouml;&szlig;er-Zeichen als <b>&lt; <\/b>und das Kleiner-Zeichen als <b>&gt;<\/b>. F&uuml;r jede Schaltfl&auml;che haben wir ein Attribut namens <b>Click <\/b>angelegt, f&uuml;r das wir den Namen der beim Anklicken auszuf&uuml;hrenden Ereignismethode angeben. Um die Eigenschaft schnell zu f&uuml;llen, geben Sie das erste Anf&uuml;hrungszeichen ein und w&auml;hlen dann den IntelliSense-Eintrag <b>Neuer Ereignishandler <\/b>aus. Dadurch werden dann auch direkt die entsprechenden, noch leeren Ereignismethoden in der Code behind-Klasse erstellt.<\/p>\n<h2>Anzeigen des ersten Datensatzes<\/h2>\n<p>Damit beim &Ouml;ffnen des Fensters direkt der erste Datensatz der Datenherkunft angezeigt wird, haben wir eine Konstruktor-Methode hinterlegt, welche die folgenden Befehle ausf&uuml;hrt. Als Erstes f&uuml;llen wir dabei die Variable <b>dbContext <\/b>mit einer neuen Instanz unserer Context-Klasse <b>BestellverwaltungContext<\/b>. Dann f&uuml;llen wir die Auflistung <b>Kunden <\/b>mit einer <b>ObservableCollection<\/b>, die alle Eintr&auml;ge des <b>DbSet<\/b>-Objekts <b>Kunden <\/b>liefert. Schlie&szlig;lich f&uuml;llen wir die Eigenschaft <b>Kunde <\/b>mit dem ersten Element der Auflistung <b>Kunden <\/b>(<b>Kunden.First()<\/b>) und f&uuml;llen auch noch die Auflistung <b>Anreden<\/b>, welche die Datens&auml;tze f&uuml;r das <b>ComboBox<\/b>-Element <b>Anreden <\/b>enth&auml;lt:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>New()\r\n     InitializeComponent()\r\n     dbContext = <span style=\"color:blue;\">New<\/span> BestellverwaltungContext\r\n     Kunden = <span style=\"color:blue;\">New<\/span> ObservableCollection(Of Kunde)(dbContext.Kunden)\r\n     Kunde = Kunden.First()\r\n     Anreden = <span style=\"color:blue;\">New<\/span> List(Of Anrede)(dbContext.Anreden)\r\n     DataContext = Me\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Ereignismethoden f&uuml;llen<\/h2>\n<p>Damit zeigt das Fenster nun immer den ersten Datensatz an. Wir wollen aber mit den bereits angelegten Schaltfl&auml;chen zwischen den Datens&auml;tzen navigieren k&ouml;nnen. Dazu schauen wir uns zun&auml;chst an, wie wir vom aktuellen Datensatz zum n&auml;chsten Datensatz gelangen, also zum zweiten Datensatz der <b>ObservableCollection <\/b>namens <b>Kunden<\/b>.<\/p>\n<p>Das Problem ist, dass wir nicht durch eine ObservableCollection navigieren k&ouml;nnen wie etwa durch ein Recordset und seinen Methoden <b>MoveNext<\/b>, <b>MovePrevious <\/b>und so weiter. Wir k&ouml;nnen aber immerhin die Methode Item() mit dem gew&uuml;nschten Index nutzen, um ein anderes Element zu referenzieren. Im folgenden Code-Beispiel weisen wir der Variablen <b>Kunde <\/b>etwa das zweite Element der Kundenliste zu:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>btnNaechster_Click(sender<span style=\"color:blue;\"> As Object<\/span>, e<span style=\"color:blue;\"> As <\/span>RoutedEventArgs)\r\n     Kunde = Kunden.Item(1)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wenn wir das Projekt nun allerdings starten und auf die Schaltfl&auml;che <b>btnNaechster <\/b>klicken, wird immer noch der erste Datensatz angezeigt.<\/p>\n<p>Der Grund ist schnell gefunden: Wir haben keinerlei Mechanismus implementiert, der daf&uuml;r sorgen w&uuml;rde, dass &Auml;nderungen an dem in der Eigenschaft <b>Kunde <\/b>gespeicherten Element sich auf die Benutzeroberfl&auml;che auswirken beziehungsweise die Daten eines neu zugewiesenen <b>Kunde<\/b>-Elements angezeigt w&uuml;rden. F&uuml;r diesen Fall ist die Schnittstelle <b>INotifyPropertyChanged <\/b>vorgesehen. Diese m&uuml;ssen wir in der Code behind-Klasse implementieren. Dazu f&uuml;gen wir zun&auml;chst einen Verweis auf den Namespace <b>System.ComponentModel <\/b>hinzu:<\/p>\n<pre>Imports System.ComponentModel<\/pre>\n<p>Die Schnittstelle <b>INotifyPropertyChanged <\/b>m&uuml;ssen wir nun f&uuml;r die Klasse <b>frmKundendetails <\/b>implementieren. Dazu h&auml;ngen wir in der Zeile unter der Definition der Klasse die folgende Zeile an:<\/p>\n<pre><span style=\"color:blue;\">Public Class<\/span> frmKundendetails\r\n     Implements INotifyPropertyChanged\r\n     ...\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Anschlie&szlig;end klicken Sie mit der rechten Maustaste auf <b>INotifyPropertyChanged<\/b>, w&auml;hlen den Kontextmen&uuml;-Eintrag <b>Schnellaktionen und Refactorings&#8230; <\/b>aus und klicken dann auf <b>Schnittstelle implementieren <\/b>(siehe Bild 2). Daraufhin f&uuml;gt Visual Studio die folgende Anweisung zur Klasse hinzu:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_174_002.png\" alt=\"Implementieren der Schnittstelle INotifyPropertyChanged\" width=\"700\" height=\"235,7664\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Implementieren der Schnittstelle INotifyPropertyChanged<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Event PropertyChanged<span style=\"color:blue;\"> As <\/span>PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged<\/pre>\n<p>Nun m&uuml;ssen wir noch daf&uuml;r sorgen, dass dieses Ereignis beim &Auml;ndern der Eigenschaft <b>Kunde <\/b>ausgel&ouml;st wird. Das erreichen wir durch Hinzuf&uuml;gen einer Zeile zur Definition der entsprechenden Property:<\/p>\n<pre><span style=\"color:blue;\">Public Property <\/span>Kunde\r\n     Get\r\n         Return _Kunde\r\n     End Get\r\n     <span style=\"color:blue;\">Set<\/span>\r\n         _Kunde = Value\r\n         RaiseEvent PropertyChanged(Me, <span style=\"color:blue;\">New<\/span> PropertyChangedEventArgs(\"Kunde\"))\r\n     End <span style=\"color:blue;\">Set<\/span>\r\n<span style=\"color:blue;\">End Property<\/span><\/pre>\n<p>Wenn wir nun das Projekt neu starten und mit der Schaltfl&auml;che <b>btnNaechster <\/b>den Kunden wechseln wollen, wird dieser auch angezeigt.<\/p>\n<p><b>Hinweis: <\/b>Diese &Auml;nderung wurde bereits in den Code zum Erstellen der Code behind-Klasse von Access aus hinzugef&uuml;gt.<\/p>\n<h2>Erster, vorheriger, n&auml;chster und letzter Datensatz<\/h2>\n<p>Damit k&ouml;nnen wir uns nun im Detail um die vier Schaltfl&auml;chen <b>btnErster<\/b>, <b>btnVorheriger<\/b>, <b>btnNaechster <\/b>und <b>btnLetzter <\/b>k&uuml;mmern. Den ersten Kunden finden wir leicht &uuml;ber die Methode <b>First <\/b>der <b>Kunden<\/b>-Auflistung. Also f&uuml;llen wir die Methode <b>btnErster_Click <\/b>wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>btnErster_Click(sender<span style=\"color:blue;\"> As Object<\/span>, e<span style=\"color:blue;\"> As <\/span>RoutedEventArgs)\r\n     Kunde = Kunden.First\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<div class=\"rcp_restricted\"><p><span style=\"color: #ff0000;\">M&ouml;chten Sie weiterlesen? Dann l&ouml;sen Sie Ihr Ticket!<\/span><br \/>\n<span style=\"color: #ff0000;\">Hier geht es zur Bestellung des Jahresabonnements des Magazins <strong>Visual Basic Entwickler<\/strong>:<\/span><br \/>\n<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/shop.minhorst.com\/magazine\/363\/visual-basic-entwickler-jahresabonnement?c=77\">Zur Bestellung ...<\/a><\/span><br \/>\n<span style=\"color: #ff0000;\">Danach greifen Sie sofort auf <strong>alle rund 200 Artikel<\/strong> unseres Angebots zu - auch auf diesen hier!<\/span><br \/>\n<span style=\"color: #000000;\">Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:<\/span><\/p>\n<\/div>\n\n\t\n\t<form id=\"rcp_login_form\"  class=\"rcp_form\" method=\"POST\" action=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000174\/\">\n\n\t\t\n\t\t<fieldset class=\"rcp_login_data\">\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_login\">Username or Email<\/label>\n\t\t\t\t<input name=\"rcp_user_login\" id=\"rcp_user_login\" class=\"required\" type=\"text\"\/>\n\t\t\t<\/p>\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_pass\">Password<\/label>\n\t\t\t\t<input name=\"rcp_user_pass\" id=\"rcp_user_pass\" class=\"required\" type=\"password\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t\t<p>\n\t\t\t\t<input type=\"checkbox\" name=\"rcp_user_remember\" id=\"rcp_user_remember\" value=\"1\"\/>\n\t\t\t\t<label for=\"rcp_user_remember\">Remember me<\/label>\n\t\t\t<\/p>\n\t\t\t<p class=\"rcp_lost_password\"><a href=\"\/data\/wp\/v2\/posts\/55000174?rcp_action=lostpassword\"><\/a><\/p>\n\t\t\t<p>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_action\" value=\"login\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_redirect\" value=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000174\/\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_login_nonce\" value=\"dbce743e9d\"\/>\n\t\t\t\t<input id=\"rcp_login_submit\" class=\"rcp-button\" type=\"submit\" value=\"Login\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t<\/fieldset>\n\n\t\t\n\t<\/form>\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wenn Sie und Ihre Kunden die Arbeit mit der Detailansicht von Access-Formularen gewohnt sind, m&ouml;chten Sie vielleicht auch in einem WPF-Fenster mit der Detailansicht der Daten einer Klasse bl&auml;ttern k&ouml;nnen. Dieser Artikel zeigt, wie Sie einem Detailformular die Daten einer Tabelle &uuml;ber die entsprechende DbSet-Auflistung zuweisen und wie Sie mit entsprechenden Schaltfl&auml;chen in den Datens&auml;tzen bl&auml;ttern k&ouml;nnen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66022019,662019,44000002,44000021],"tags":[],"yst_prominent_words":[],"class_list":["post-55000174","post","type-post","status-publish","format-standard","hentry","category-66022019","category-662019","category-Benutzeroberflaeche_mit_WPF","category-Entity_Framework"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000174","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000174"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000174\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000174"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000174"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000174"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}