{"id":55000087,"date":"2017-06-01T00:00:00","date_gmt":"2020-03-27T19:26:34","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=87"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"EDM_Bilder_speichern_und_anzeigen","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/EDM_Bilder_speichern_und_anzeigen\/","title":{"rendered":"EDM: Bilder speichern und anzeigen"},"content":{"rendered":"<p><b>In der Bestellverwaltung haben wir bisher nur mit einfachen Daten in Datentypen wie Text, Zahl oder Datum gearbeitet. Dabei kann man doch mit WPF auch wunderbar Bilddateien anzeigen. In diesem Artikel erweitern wir die Datenbank Bestellverwaltung um das Speichern und die Anzeige von Bildern zu den Produktdatens&auml;tzen.<\/b><\/p>\n<h2>Speicherort: Tabellenfeld oder Dateisystem<\/h2>\n<p>Eine der wichtigsten Fragen, wenn es darum geht, Bilder mit einer Datenbank zu verwalten, ist die nach dem Speicherort der Bilder. Grunds&auml;tzlich gibt es zwei einfache Varianten: Die Bilder werden im Dateisystem gespeichert und die Datenbank h&auml;lt nur die Dateipfade zu den Bildern in den jeweiligen Datens&auml;tzen vor. Oder Sie speichern die Bilder direkt in einem entsprechenden Feld in der Datenbank. Wir werden an dieser Stelle, an der wir mit einer SQLite-Datenbank arbeiten, die Variante mit dem Dateisystem w&auml;hlen, und zwar aus folgenden Gr&uuml;nden:<\/p>\n<ul>\n<li>Datenbanken sind dazu gemacht, referenziell verkn&uuml;pfte Daten zu speichern, diese zu indizieren und schnell zugreifbar zu machen oder zu &auml;ndern. Das Speichern von Bildern oder anderen Dateien in den Tabellen der Datenbank ist da eher kontraproduktiv.<\/li>\n<li>Wenn Sie die Bilder in der Datenbankdatei speichern und die Daten sichern wollen, m&uuml;ssen Sie immer die komplette Datenbank inklusive der enthaltenen Bilder sichern. Wenn sich die Bilder im Dateisystem etwa in einem Ordner im gleichen Verzeichnis wie die Datenbank befinden, k&ouml;nnen diese separat gesichert werden, was nur dann n&ouml;tig ist, wenn sich diese ge&auml;ndert haben.<\/li>\n<li>Zum Bearbeiten oder Anzeigen m&uuml;ssen die Bilder in der Regel entweder ohnehin im Dateisystem gespeichert oder aber anderweitig in den Speicher geladen werden. Dann kann man sie auch direkt aus dem Dateisytem heraus &ouml;ffnen.<\/li>\n<\/ul>\n<p>Optimalerweise speichern wir die Bilder auch noch in einem Verzeichnis, dass sich auf der gleichen Ebene oder unterhalb der Anwendung befindet. Auf diese Weise brauchen wir nur den relativen Pfad zur Bilddatei in der Datenbank zu speichern.<\/p>\n<h2>Tabelle Produkte erweitern<\/h2>\n<p>Damit wir die Bilder, die wir im Dateisystem speichern, mit den Datens&auml;tzen der Tabelle <b>Produkte <\/b>verkn&uuml;pfen k&ouml;nnen, f&uuml;gen wir dieser Tabelle ein Feld namens Bild hinzu. Es soll ein einfaches Textfeld sein, dass den Pfad zur Bilddatei speichert, und zwar relativ zur Datenbank in einem eigenen Ordner namens <b>Bilder<\/b>.<\/p>\n<p>Diese &Auml;nderung nehmen wir der Einfachheit halber &uuml;ber das Tool <b>SQLiteStudio <\/b>vor. Dort &ouml;ffnen Sie die Datenbank <b>Bestellverwaltung <\/b>und klicken dann doppelt auf die Tabelle <b>Produkte<\/b>. Nun bet&auml;tigen Sie die Schaltfl&auml;che <b>Add column (Ins) <\/b>wie in Bild 1.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_03\/pic_87_001.png\" alt=\"Anlegen eines neuen Feldes\" width=\"549,6265\" height=\"297,3391\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Anlegen eines neuen Feldes<\/span><\/b><\/p>\n<p>Dies &ouml;ffnet den Dialog aus Bild 2. Hier tragen Sie den Namen des neuen Feldes sowie den Datentyp ein. Anschlie&szlig;end schlie&szlig;en Sie den Dialog mit der <b>OK<\/b>-Schaltfl&auml;che.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_03\/pic_87_002.png\" alt=\"Anlegen des Feldes Bild\" width=\"424,7115\" height=\"390,8144\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Anlegen des Feldes Bild<\/span><\/b><\/p>\n<p>Erst der Klick auf die Schaltfl&auml;che <b>Commit structure changes <\/b>&ouml;ffnet den Dialog <b>Auszuf&uuml;hrende Abfragen<\/b>, der die SQL-Abfragen mit den geplanten &Auml;nderungen anzeigt und per Klick auf <b>OK <\/b>die &Auml;nderung in die Datenbank &uuml;bertr&auml;gt (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_03\/pic_87_003.png\" alt=\"SQL-Anweisung zum Anlegen der Tabelle mit dem Feld Bild\" width=\"499,6607\" height=\"361,7581\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: SQL-Anweisung zum Anlegen der Tabelle mit dem Feld Bild<\/span><\/b><\/p>\n<p>Nun m&uuml;ssen wir die &Auml;nderung in der Datenbank noch in das Entity Data Model &uuml;bertragen. Dazu &ouml;ffnen Sie die Ansicht <b>Bestellverwaltung.edmx <\/b>und w&auml;hlen aus dem Kontextmen&uuml; den Eintrag <b>Modell aus der Datenbank aktualisieren&#8230; <\/b>aus (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_03\/pic_87_004.png\" alt=\"Aktualisieren des Entity Data Models\" width=\"499,6607\" height=\"294,9502\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Aktualisieren des Entity Data Models<\/span><\/b><\/p>\n<p>Danach erscheint das Feld <b>Bild <\/b>dann auch im Element <b>Produkt <\/b>des Entity Data Models. Nun k&ouml;nnen wir also Bildpfade zum Feld <b>Bild <\/b>des Elements <b>Produkt <\/b>hinzuf&uuml;gen. Damit sind die Arbeiten am Entity Framework erledigt.<\/p>\n<h2>XAML-Code definieren<\/h2>\n<p>Nun wollen wir das Aussehen des Fensters zur Anzeige der Produktdaten mit den Bildern definieren. Dies erledigen wir diesmal gleich im Fenster <b>MainWindow.XAML<\/b>. Damit die Steuer-elemente wie gew&uuml;nschten angeordnet werden, haben wir &uuml;ber die Elemente <b>Grid.RowDefinitions <\/b>und <b>Grid.ColumnDefinitions <\/b>einige Zeilen und Spalten definiert. Die Definition dieser Elemente sieht wie folgt aus, wobei die Position des Elements mit dem Wert <b>* <\/b>f&uuml;r das Attribut <b>Height <\/b>eine besondere Rolle spielt:<\/p>\n<pre>&lt;Grid.RowDefinitions&gt;\r\n     &lt;RowDefinition Height=\"Auto\"&gt;&lt;\/RowDefinition&gt; \/\/f&uuml;r Header\r\n     &lt;RowDefinition Height=\"Auto\"&gt;&lt;\/RowDefinition&gt; \/\/f&uuml;r ListBox\r\n     &lt;RowDefinition Height=\"Auto\"&gt;&lt;\/RowDefinition&gt; \/\/f&uuml;r ID des Produkts\r\n     &lt;RowDefinition Height=\"Auto\"&gt;&lt;\/RowDefinition&gt; \/\/f&uuml;r Bezeichnung\r\n     &lt;RowDefinition Height=\"Auto\"&gt;&lt;\/RowDefinition&gt; \/\/f&uuml;r Bildpfad\r\n     &lt;RowDefinition Height=\"*\"&gt;&lt;\/RowDefinition&gt; \/\/f&uuml;r Image-Steuerelement\r\n     &lt;RowDefinition Height=\"Auto\"&gt;&lt;\/RowDefinition&gt; \/\/f&uuml;r Schaltfl&auml;chen\r\n&lt;\/Grid.RowDefinitions&gt;\r\n&lt;Grid.ColumnDefinitions&gt;\r\n     &lt;ColumnDefinition Width=\"Auto\"&gt;&lt;\/ColumnDefinition&gt;\r\n     &lt;ColumnDefinition Width=\"*\"&gt;&lt;\/ColumnDefinition&gt;\r\n&lt;\/Grid.ColumnDefinitions&gt;<\/pre>\n<p>Hier hinterlegen wir nun das <b>ListBox<\/b>-Steuerelement, das in der zweiten Zeile &uuml;ber zwei Spalten angeordnet werden soll. Dieses f&uuml;gen wir in der folgenden Form zum XAML-Code hinzu:<\/p>\n<pre>&lt;ListBox x:Name=\"lstProdukte\" Grid.Row=\"1\" Grid.ColumnSpan=\"2\" Margin=\"5\" ItemsSource=\"{Binding Produkte}\" DisplayMemberPath=\"Bezeichnung\" SelectionChanged=\"lstProdukte_SelectionChanged\"\/&gt;<\/pre>\n<p>Das <b>ListBox<\/b>-Element hei&szlig;t <b>lstProdukte <\/b>und ist an die Auflistung <b>Produkte <\/b>als <b>ItemsSource <\/b>gebunden. Angezeigt soll der Inhalt der Eigenschaft <b>Bezeichnung <\/b>des gebundenen Objekts. Wenn sich die Auswahl &auml;ndert, etwa weil der Benutzer ein anderes Element anklickt, soll dies die Ereignisprozedur <b>lstProdukte_SelectionChanged <\/b>ausl&ouml;sen. Damit das <b>ListBox<\/b>-Element die Elemente der Produkte auflistet, f&uuml;gen wir der Code behind-Klasse <b>MainWindow.xaml.cs <\/b>einige Codezeilen hinzu. Den Beginn macht die klassenweite Definition des <b>DBContext<\/b>-Elements:<\/p>\n<pre>BestellverwaltungEntities dbContext;<\/pre>\n<p>Damit wir die Produkte als Datenherkunft f&uuml;r die ListBox haben und das einzelne Produkt-Objekt als Datenherkunft f&uuml;r die Steuer-elemente des Fensters, definieren wir au&szlig;erdem noch eine private Variable f&uuml;r die Liste der Produkte, und zwar f&uuml;r eine ObservableCollection mit Elementen des Typs <b>Produkt<\/b>:<\/p>\n<pre>private ObservableCollection&lt;Produkt&gt; produkte;<\/pre>\n<p>Den Inhalt dieser Variablen wollen wir auch &ouml;ffentlich zug&auml;nglich machen, damit wir die Elemente des XAML-Codes daran binden k&ouml;nnen. Dies erledigen wir wie folgt:<\/p>\n<pre>public ObservableCollection&lt;Produkt&gt; Produkte {\r\n     get { return produkte; }\r\n     set { produkte = value; }\r\n}<\/pre>\n<p>Auch f&uuml;r das jeweils mit den Textfeldern anzuzeigende Produkt, dessen Bild wir ja auch laden wollen, deklarieren wir ein Objekt namens <b>produkt<\/b>, dass eine Instanz des Typs <b>Produkt <\/b>speichern kann:<\/p>\n<pre>private Produkt produkt;<\/pre>\n<p>Die &ouml;ffentliche Eigenschaft kann &uuml;ber den Namen <b>Produkt <\/b>gelesen und geschrieben werden. Damit beim F&uuml;llen der Variablen <b>produkt <\/b>gleich die daran gebundenen Steuerelemente aktualisiert werden, implemtieren wir die Schnittstelle <b>INotifyPropertyChanged <\/b>f&uuml;r die aktuelle Klasse. Der Teil in der &ouml;ffentlichen Eigenschaft Produkt erh&auml;lt dazu im Setter einen Aufruf der Methode <b>OnPropertyChanged<\/b>:<\/p>\n<pre>public Produkt Produkt {\r\n     get { return produkt; }\r\n     set {\r\n         produkt = value;\r\n         OnPropertyChanged(new PropertyChangedEventArgs(\"Produkt\"));\r\n     }\r\n}<\/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\/55000087\/\">\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\/55000087?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\/55000087\/\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_login_nonce\" value=\"7c46eb013a\"\/>\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>In der Bestellverwaltung haben wir bisher nur mit einfachen Daten in Datentypen wie Text, Zahl oder Datum gearbeitet. Dabei kann man doch mit WPF auch wunderbar Bilddateien anzeigen. In diesem Artikel erweitern wir die Datenbank Bestellverwaltung um das Speichern und die Anzeige von Bildern zu den Produktdatens&auml;tzen.<\/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":[662017,66032017,44000021,44000023,44000003,44000015],"tags":[],"yst_prominent_words":[],"class_list":["post-55000087","post","type-post","status-publish","format-standard","hentry","category-662017","category-66032017","category-Entity_Framework","category-PowerApps","category-WPFGrundlagen","category-WPFSteuerelemente"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000087","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=55000087"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000087\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000087"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000087"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000087"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000087"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}