{"id":55001094,"date":"2017-08-01T00:00:00","date_gmt":"2020-05-13T21:26:12","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1094"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Datenzugriff_per_VSTOAddIn","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/","title":{"rendered":"Datenzugriff per VSTO-Add-In"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg09.met.vgwort.de\/na\/99aed82cac1842099e731307ceca73a3\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Im Beitrag &#8222;Access-Add-In mit VSTO&#8220; haben Sie erfahren, wie Sie aus einer der bestehenden Vorlagen f&uuml;r Outlook-, Word- oder Excel-Add-Ins ein Access-Add-In zaubern. In diesem Beitrag nun wollen wir uns ansehen, wie Sie von einem solchen Add-In auf die Objekte der Datenbank und auch auf die darin enthaltenen Daten zugreifen k&ouml;nnen. Damit erhalten Sie die Grundlage, viele interessante und praktische Add-Ins f&uuml;r Access zu bauen.<\/b><\/p>\n<p>Wenn Sie ein Add-In f&uuml;r eine Access-Anwendung programmieren, wollen Sie damit nicht irgendwelche Funktionen ausf&uuml;hren, sondern solche, welche die Funktionen von Access oder die Daten der aktuellen Datenbank nutzen. Dazu m&uuml;ssen Sie innerhalb des Visual Studio-Projekts auf die Access-Instanz zugreifen k&ouml;nnen, von der aus das Add-In gestartet wurde. Dar&uuml;ber k&ouml;nnen Sie dann die Daten der aktuell geladenen Datenbank lesen.<\/p>\n<p>Wie aber kommen wir an die Access-Instanz Das ist, im Vergleich zu fr&uuml;heren Vorgehensweisen in Zusammenhang mit COM-Add-Ins f&uuml;r Office-Anwendungen, wesentlich leichter geworden. Genau genommen stellt die Klasse <b>ThisAddIn.Designer.vb <\/b>dieses Objekt &uuml;ber die Variable <b>Application <\/b>zur Verf&uuml;gung (s. Bild 1). Weiter unten finden Sie dann in der gleichen Klasse die Methode Initialize, welche die Application-Eigenschaft mit einem Verweis auf die als Host verwendete Datei f&uuml;llt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_001_.png\" alt=\"Variable zur Bereitstellung des Application-Objekts\" width=\"549,6265\" height=\"230,8752\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Variable zur Bereitstellung des Application-Objekts<\/span><\/b><\/p>\n<p>Dies ist der Hintergrund, f&uuml;r uns ist aber vielmehr wichtig, dass wir &uuml;ber <b>Application <\/b>jederzeit die als Host dienende Access-Anwendung referenzieren k&ouml;nnen. Dies schauen wir uns an einem einfachen Beispiel an, wobei wir das im Beitrag <b>Access-Add-In mit VSTO <\/b>(<b>www.access-im-unternehmen.de\/1092<\/b>) erstellte Visual Basic-Add-In als Grundlage verwenden, das Sie auch im Download zum vorliegenden Beitrag finden.<\/p>\n<p>Hier f&uuml;gen wir der Methode <b>ThisAddIn_Startup <\/b>im Klassenmodul <b>ThisAddIn.vb <\/b>einfach eine Anweisung hinzu, welche den Namen der mit dem <b>Application<\/b>-Objekt gelieferten Anwendung liefert:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ThisAddIn_Startup() Handles Me.Startup\r\n     MessageBox.Show(\"Application.Name: \" + Application.Name)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Dies zeigt beim &ouml;ffnen von Access nach dem Starten des Add-Ins (und sp&auml;ter auch beim &ouml;ffnen ohne vorheriges Starten des Add-Ins, das ja dann weiterhin &uuml;ber die Registry aufgerufen wird) eine Meldung mit dem Namen <b>Microsoft Access <\/b>an. Wer fr&uuml;her einmal COM-Add-Ins f&uuml;r Access programmiert hat, wei&szlig;, dass damit mehr benutzerdefinierter Aufwand verbunden war.<\/p>\n<h2>Ge&ouml;ffnete Datenbank referenzieren<\/h2>\n<p>Etwas komplizierter wird es, wenn Sie vom Add-In aus die ge&ouml;ffnete Datenbank referenzieren m&ouml;chten. Das Problem dabei ist, dass das Add-In ja bereits beim Starten von Access geladen wird und &uuml;ber die Objektvariable <b>Application <\/b>verf&uuml;gbar ist. Zu diesem Zeitpunkt ist aber noch keine Access-Datenbank in Access ge&ouml;ffnet. Dies geschieht erst sp&auml;ter. Wir m&uuml;ssen also einen Weg finden, um zu erkennen, wann Access eine Datenbankdatei &ouml;ffnet, und diese dann referenzieren. Wir probieren zuerst einmal aus, was geschieht, wenn wir die Methode <b>ThisAddIn_Startup <\/b>wie folgt ausstatten:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ThisAddIn_Startup() Handles Me.Startup\r\n     <span style=\"color:blue;\">If <\/span>Application.CurrentDb Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         MessageBox.Show(\"DB ist nicht geladen.\")\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         MessageBox.Show(\"DB: \" + Application.CurrentDb.Name)\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit das <b>MessageBox<\/b>-Objekt verf&uuml;gbar ist, f&uuml;gen Sie noch den folgenden Verweis auf den Namespace <b>System.Windows.Forms <\/b>hinzu:<\/p>\n<pre>Imports System.Windows.Forms<\/pre>\n<p>Die Prozedur pr&uuml;ft nun mit <b>CurrentDb Is Nothing<\/b>, ob es eine aktuelle Datenbankdatei gibt, und liefert eine entsprechende Meldung. Das Ergebnis: Wenn man Access ohne Datenbank &ouml;ffnet, hat <b>CurrentDb <\/b>den Wert <b>Nothing<\/b>, wenn man es direkt mit einer Datenbank startet, enth&auml;lt <b>CurrentDb <\/b>einen Verweis auf die geladene Datenbank. Dann gibt die <b>MessageBox.Show<\/b>-Methode den Pfad zur geladenen Datenbank aus. Wenn wir allerdings Access starten und erst dann eine Datenbank &ouml;ffnen, erkennt das Add-In zwar beim Starten von Access, dass noch keine Datenbank ge&ouml;ffnet ist, aber wenn wir dann nachtr&auml;glich eine Datenbank &ouml;ffnen, l&ouml;st dies kein Ereignis mehr aus, aufgrund dessen wir erkennen k&ouml;nnten, dass eine Datenbank ge&ouml;ffnet wurde.<\/p>\n<p>Warum aber m&uuml;ssen wir so genau wissen, ob gerade eine Datenbank geladen ist oder nicht Ganz einfach: Wir wollen ja beispielsweise &uuml;ber das Ribbon Funktionen anbieten, mit denen der Benutzer auf die Objekte oder Daten der aktuellen Datenbank zugreifen kann. Wir k&ouml;nnten zwar einfach beim Bet&auml;tigen der entsprechenden Elemente pr&uuml;fen, ob aktuell eine Datenbank ge&ouml;ffnet ist, und gegebenenfalls eine Meldung ausgeben, dass die Funktion nur bei ge&ouml;ffneter Datenbank zur Verf&uuml;gung steht. Aber schicker w&auml;re es nat&uuml;rlich, wenn solche Schaltfl&auml;chen deaktiviert sind, wenn die Funktionen nicht zur Verf&uuml;gung stehen.<\/p>\n<h2>Timer mit Datenbankerkennung<\/h2>\n<p>Wir wollen nun einen Timer zum Add-In hinzuf&uuml;gen, der in jeder Sekunde einmal pr&uuml;ft, ob eine Datenbank ge&ouml;ffnet ist. Wenn eine Datenbank ge&ouml;ffnet ist, soll ein Meldungsfenster erscheinen und den Pfad zur ge&ouml;ffneten Datenbank anzeigen. Dazu f&uuml;gen wir der Klasse <b>ThisAddIn.vb <\/b>folgenden Verweis auf den Namespace <b>SystemThreading.Tasks <\/b>hinzu:<\/p>\n<pre>Imports System.Threading.Tasks<\/pre>\n<p>Wir ben&ouml;tigen eine <b>Boolean<\/b>-Variable namens <b>Loaded<\/b>, welche den Zustand speichert, ob eine Datenbank geladen ist oder nicht:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Loaded<span style=\"color:blue;\"> As Boolean<\/span><\/pre>\n<p>Schlie&szlig;lich erweitern wir die Methode <b>ThisAddIn_Startup <\/b>so, dass diese einen Timer auf Basis der gleichnamigen Klasse erstellt, der alle 1.000 Millisekunden aufgerufen werden soll. F&uuml;r diese Klasse legen wir einen Handler an, der durch das Ereignis <b>Elapsed <\/b>des Timers ausgel&ouml;st wird und die Methode <b>HandleTimer <\/b>aufruft. Dann starten wir den Timer mit der <b>Start<\/b>-Methode:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ThisAddIn_Startup() Handles Me.Startup\r\n     <span style=\"color:blue;\">Dim <\/span>timer<span style=\"color:blue;\"> As <\/span>System.Timers.Timer\r\n     timer = <span style=\"color:blue;\">New<\/span> System.Timers.Timer(1000)\r\n     AddHandler timer.Elapsed, AddressOf HandleTimer\r\n     <span style=\"color:blue;\">With<\/span> timer\r\n         .Start()\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die als Ereignishandler festgelegte Prozedur <b>HandleTimer <\/b>sieht wie in Listing 1 aus. F&uuml;r VBA-erprobte Entwickler sieht der Aufbau etwas gew&ouml;hnungsbed&uuml;rftig aus. Es handelt sich dabei um eine sogenannte asynchron laufende Methode, die mehrfach aufgerufen werden kann, auch wenn die aktuelle Instanz noch nicht abgearbeitet ist. So k&ouml;nnen wir die Methode tats&auml;chlich jede Sekunde aufrufen, auch wenn der Benutzer noch nicht die durch den vorherigen Aufruf angezeigte <b>MessageBox <\/b>geschlossen hat. Das kann dann schnell un&uuml;bersichtlich werden, wenn man nicht sauber codiert hat und pl&ouml;tzlich eine MessageBox nach der anderen auf dem Bildschirm erscheint. F&uuml;r den Fall, dass Ihnen das einmal geschieht, k&ouml;nnen Sie schnell zu Visual Studio wechseln und dort <b>Umschalt + F5 <\/b>klicken &#8211; dann ist der Spuk vorbei. Falls Sie das Add-In gerade nicht im Kontext des Debuggens von Visual Studio aus gestartet haben, m&uuml;ssen Sie wohl den Task-Manager bem&uuml;hen.<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Async Sub HandleTimer(sender<span style=\"color:blue;\"> As Object<\/span>, e<span style=\"color:blue;\"> As <\/span>EventArgs)\r\n     Await Task.Run(\r\n         Sub()\r\n             <span style=\"color:blue;\">If <\/span>Application.CurrentDb Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>Loaded = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                     Loaded = <span style=\"color:blue;\">False<\/span>\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>Loaded = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                     Loaded = <span style=\"color:blue;\">True<\/span>\r\n                     MessageBox.Show(\"Geladen: \" + Application.CurrentDb.Name + \" \" + Loaded.ToString())\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         End Sub\r\n     )\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Ereignisprozedur, die nach Ablauf des Timers ausgel&ouml;st wird<\/span><\/b><\/p>\n<p>Nun zu der Methode: Sie enth&auml;lt innerhalb der Anweisung <b>Await Task.Run <\/b>eine weitere Methode, die bei jedem Aufruf ausgef&uuml;hrt wird. Diese Methode pr&uuml;ft, ob eine Datenbank geladen ist (<b>Application.CurrentDb Is Nothing<\/b>). Ist das nicht der Fall, pr&uuml;ft sie den Wert der Variablen <b>Loaded <\/b>und stellt diesen im Falle des Wertes <b>True <\/b>auf <b>False <\/b>ein. Beim &ouml;ffnen von Access ohne Datenbank geschieht also nichts weiter &#8211; <b>CurrentDb <\/b>ist <b>Nothing <\/b>und <b>Loaded <\/b>hat den Wert <b>False<\/b>.<\/p>\n<p>Interessant wird es, wenn eine Datenbank ge&ouml;ffnet wird. Dann ist <b>CurrentDb <\/b>nicht mehr <b>Nothing <\/b>und der <b>Else<\/b>-Teil der &auml;u&szlig;eren <b>If&#8230;Then<\/b>-Bedingung wird aufgerufen. <b>Loaded <\/b>hat bis dahin den Wert <b>False <\/b>und wird auf <b>True <\/b>eingestellt. Au&szlig;erdem gibt die Methode als Zeichen, dass sie erkannt hat, dass eine Datenbank geladen wurde, den Namen der Datenbank per MessageBox aus. Beim n&auml;chsten Durchgang wird dann, weil <b>CurrentDb <\/b>nicht <b>Nothing <\/b>ist, wieder der <b>Else<\/b>-Teil der &auml;u&szlig;eren Bedingung angesteuert. Diesmal hat <b>Loaded <\/b>aber den Wert <b>False<\/b>, weshalb die <b>MessageBox <\/b>nicht erneut angezeigt wird.<\/p>\n<p>Was machen wir nun mit dieser Methode, die nach dem &ouml;ffnen einer Datenbank eine MessageBox anzeigt Wir k&ouml;nnen zum Beispiel statt des &ouml;ffnens der MessageBox Code ausf&uuml;hren, der daf&uuml;r sorgt, dass die gew&uuml;nschten Ribbon-Elemente, die wir f&uuml;r die Bearbeitung der Datenbank hinzuf&uuml;gen, aktiviert oder deaktiviert werden. Das schauen wir uns einmal an einer einzelnen Ribbon-Schaltfl&auml;che an.<\/p>\n<h2>Ribbon hinzuf&uuml;gen<\/h2>\n<p>Um eine Ribbon-Definition hinzuzuf&uuml;gen, die alle Elemente des Access-Ribbons abbilden kann, k&ouml;nnen wir leider nicht das Element <b>Men&uuml;band (Visueller Designer) <\/b>des Dialogs <b>Neues Element hinzuf&uuml;gen <\/b>nutzen, das wir mit dem Kontextmen&uuml;-Befehl <b>Hinzuf&uuml;gen|Neues Element&#8230; <\/b>des Projekt-Elements im Projektmappen-Explorer &ouml;ffnen.  Stattdessen f&uuml;gen wir das Element <b>Men&uuml;band (XML) <\/b>hinzu, f&uuml;r das wir den Namen <b>Ribbon_Access.vb <\/b>festlegen (s. Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_002.png\" alt=\"Anlegen des Elements Men&uuml;band (XML)\" width=\"649,559\" height=\"330,3727\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Anlegen des Elements Men&uuml;band (XML)<\/span><\/b><\/p>\n<p>Aus der damit hinzugef&uuml;gten Datei <b>Ribbon_Access.vb <\/b>kopieren wir die dort noch auskommentierte Methode <b>CreateRibbonExtensibilityObject <\/b>in das Klassenmodul <b>ThisAddIn.vb <\/b>und entfernen die Kommentarzeichen:<\/p>\n<pre>Protected Overrides Function _\r\n         CreateRibbonExtensibilityObject() _\r\n        <span style=\"color:blue;\"> As <\/span>Microsoft.Office.Core.IRibbonExtensibility\r\n     Return <span style=\"color:blue;\">New<\/span> Ribbon_Access()\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Diese Methode wird beim Starten des Add-Ins automatisch ausgef&uuml;hrt. Einzelheiten zum Erstellen eines Ribbons &uuml;ber das Element <b>Men&uuml;band (XML) <\/b>finden Sie im Beitrag <b>COM-Add-In-Ribbons mit dem XML-Designer <\/b>(<b>www.access-im-unternehmen.de\/1093<\/b>).<\/p>\n<h2>Funktionen hinzuf&uuml;gen<\/h2>\n<p>Unser Add-In soll nun sowohl eine Funktion enthalten, die sich auf die Anwendung selbst bezieht, als auch eine, welche auf die Daten einer geladenen Datenbank zugreift. Auf diese Weise erhalten Sie eine gute Ausgangsposition f&uuml;r selbst programmierte Add-Ins.<\/p>\n<p>Die geplanten Funktionen sind in dem Ribbon-Tab aus Bild 3 abgebildet. Die linke Gruppe enth&auml;lt zwei Schaltfl&auml;chen, mit denen der Benutzer den Navigationsbereich ein- und ausblenden kann. Die rechte Gruppe enth&auml;lt eine Schaltfl&auml;che, welche einen Dialog zur Anzeige aller Tabellen der aktuell ge&ouml;ffneten Datenbank liefern soll. Diese Schaltfl&auml;che soll nat&uuml;rlich nur aktiviert sein, wenn Access &uuml;berhaupt eine Datenbank geladen hat.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_003.png\" alt=\"Unsere selbst erstellten Ribbon-Befehle\" width=\"649,559\" height=\"143,2453\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Unsere selbst erstellten Ribbon-Befehle<\/span><\/b><\/p>\n<p>Die Definition des Ribbons sieht wie in Listing 2 aus. Die erste Gruppe enth&auml;lt die Schaltfl&auml;chen <b>btnNavigationsbereichEinblenden <\/b>und <b>btnNavigationsbereichAusblenden<\/b>. Beide sind mit einer <b>onAction<\/b>-Callback-Eigenschaft und einem Bild ausgestattet. Die Bilder werden mit der <b>image<\/b>-Eigenschaft angegeben. F&uuml;r das Laden der Bilder ist die im Element <b>customUI <\/b>im Attribut <b>loadImage<\/b> angegebene Methode verantwortlich (mehr zum Laden von Bildern im Beitrag <b>COM-Add-In-Ribbons mit dem XML-Designer<\/b>, <b>www.access-im-unternehmen.de\/1093<\/b>). Die zweite Gruppe enth&auml;lt die Schaltfl&auml;che <b>btnTabellen<\/b>, die ebenfalls eine <b>onAction<\/b>-Eigenschaft sowie zus&auml;tzlich die Callback-Eigenschaft <b>getEnabled <\/b>enth&auml;lt.<\/p>\n<pre>&lt;xml version=\"1.0\" encoding=\"UTF-8\"&gt;\r\n&lt;customUI xmlns=\"http:\/\/schemas.microsoft.com\/office\/2009\/07\/customui\" onLoad=\"Ribbon_Load\" loadImage=\"loadImage\"&gt;\r\n   &lt;ribbon&gt;\r\n     &lt;tabs&gt;\r\n       &lt;tab id=\"tabAddIn\" label=\"COM-Add-In\"&gt;\r\n         &lt;group id=\"grpAnwendung\" label=\"Anwendung\"&gt;\r\n           &lt;button id=\"btnNavigationsbereichEinblenden\" label=\"Navigationsbereich einblenden\" onAction=\"onAction\"\r\n               image=\"window_sidebar\" size=\"large\"\/&gt;\r\n           &lt;button id=\"btnNavigationsbereichAusblenden\" label=\"Navigationsbereich ausblenden\" onAction=\"onAction\" \r\n               image=\"window_sidebar_delete\" size=\"large\"\/&gt;\r\n         &lt;\/group&gt;\r\n         &lt;group id=\"grpDatenbank\" label=\"Datenbank\"&gt;\r\n           &lt;button id=\"btnTabellen\" label=\"Tabellen anzeigen\" onAction=\"onAction\" image=\"tables\" size=\"large\" \r\n               getEnabled=\"getEnabled\"\/&gt;\r\n         &lt;\/group&gt;\r\n       &lt;\/tab&gt;\r\n     &lt;\/tabs&gt;\r\n   &lt;\/ribbon&gt;\r\n&lt;\/customUI&gt;<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Definition des Beispielribbons<\/span><\/b><\/p>\n<h2>Aktivieren und deaktivieren der Schaltfl&auml;che btnTabellen<\/h2>\n<p>Diese Schaltfl&auml;che soll ja nur aktiviert sein, wenn Access gerade eine geladene Datenbank enth&auml;lt. Wie wir dies ermitteln, haben Sie weiter oben erfahren &#8211; wir starten per Timer jede Sekunde eine Prozedur, die pr&uuml;ft, ob <b>CurrentDb <\/b>den Wert <b>Nothing <\/b>hat. Wie k&ouml;nnen wir diese nun nutzen, um die Schaltfl&auml;che <b>btnTabellen <\/b>abh&auml;ngig vom Ergebnis zu aktivieren oder zu deaktivieren Zusammengefasst gehen wir so vor: Wir f&uuml;gen der Klasse <b>Ribbon_Access.vb <\/b>eine Eigenschaft hinzu, welche den Zustand erfasst (Datenbank geladen\/nicht geladen). Diese wird von der Callback-Funktion <b>getEnabled <\/b>ausgewertet. Noch dazu machen wir in der Klasse <b>Ribbon_Access.vb<\/b> aus dem <b>IRibbonUI<\/b>-Objekt <b>Ribbon <\/b>eine Eigenschaft gleichen Namens, auf die wir von au&szlig;en zugreifen k&ouml;nnen. Damit k&ouml;nnen wir dann der Klasse <b>Ribbon_Access.vb <\/b>von au&szlig;en sowohl den Zustand Datenbank geladen\/nicht geladen mitgeben als auch daf&uuml;r sorgen, dass die Methode <b>get-Enabled <\/b>ausgel&ouml;st wird &#8211; n&auml;mlich durch Aufrufen der <b>Invalidate<\/b>-Methode des <b>IRibbonUI<\/b>-Objekts. Damit wir von der Klasse <b>This-AddIn <\/b>allerdings &uuml;berhaupt auf das <b>IRibbonUI<\/b>-Objekt zugreifen k&ouml;nnen, m&uuml;ssen wir dieses noch irgendwie innerhalb dieser Klasse referenzieren. Unter Visual Basic 2015 w&auml;re es sogar m&ouml;glich, daf&uuml;r ein Modul mit einer &ouml;ffentlichen Variablen anzulegen, aber diesen Weg wollen wir hier gezielt nicht gehen. Schauen wir uns den resultierenden Code an!<\/p>\n<h2>Ribbon in ThisAddIn.vb referenzieren<\/h2>\n<p><!--30percent--><\/p>\n<p>Die Klasse <b>ThisAddIn.vb <\/b>enth&auml;lt zwei automatisch ausgel&ouml;ste Methoden, n&auml;mlich <b>CreateRibbonExtensibility <\/b>und <b>ThisAddIn_Startup <\/b>&#8211; und zwar in dieser Reihenfolge. Wir deklarieren eine Variable des Typs <b>Ribbon_Access<\/b>, mit der wir die in <b>CreateRibbonExtensibility <\/b>erzeugte und als Funktionswert zur&uuml;ckgegebene Instanz der Klasse <b>Ribbon_Access.vb <\/b>speichern:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>objRibbon<span style=\"color:blue;\"> As <\/span>Ribbon_Access<\/pre>\n<p>Der Funktion <b>CreateRibbonExtensibility <\/b>f&uuml;gen wir dann eine Anweisung hinzu, welche die neu erzeugte Instanz von <b>Ribbon_Access <\/b>in der Variablen <b>objRibbon <\/b>speichert. Der Inhalt dieser Variablen wird dann als Funktionswert zur&uuml;ckgegeben:<\/p>\n<pre>Protected Overrides Function _\r\n         CreateRibbonExtensibilityObject() _\r\n        <span style=\"color:blue;\"> As <\/span>Microsoft.Office.Core.IRibbonExtensibility\r\n     objRibbon = <span style=\"color:blue;\">New<\/span> Ribbon_Access()\r\n     Return objRibbon\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Der in <b>objRibbon <\/b>gespeicherten Instanz der Klasse <b>Ribbon_Access.vb <\/b>wollen wir auch einen Verweis auf die Access-Anwendung, also <b>Application<\/b>, &uuml;bergeben. Das hat den Hintergrund, dass wir darin auch auf die Methoden von Access zugreifen wollen. Daher f&uuml;gen wir in der Methode <b>ThisAddIn_Startup<\/b>, die ja nach dem Erstellen von <b>Ribbon_Access <\/b>ausgel&ouml;st wird, noch eine Zeile hinzu, welche die Eigenschaft <b>Application <\/b>der Klasse <b>Ribbon_Access.vb <\/b>mit dem Verweis aus der Objektvariablen <b>Application <\/b>f&uuml;llt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ThisAddIn_Startup() Handles Me.Startup\r\n     <span style=\"color:blue;\">Dim <\/span>timer<span style=\"color:blue;\"> As <\/span>System.Timers.Timer\r\n     objRibbon.Application = Application\r\n     timer = <span style=\"color:blue;\">New<\/span> System.Timers.Timer(1000)\r\n     AddHandler timer.Elapsed, AddressOf HandleTimer\r\n     <span style=\"color:blue;\">With<\/span> timer\r\n         .Start()\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Unsere weiter oben vorgestellte <b>Timer<\/b>-Methode <b>HandleTimer <\/b>ist auch von den &auml;nderungen betroffen. In dem <b>If<\/b>-Zweig, in dem wir feststellen, dass keine Datenbank geladen ist, stellen wir die Eigenschaft <b>DatenbankGeladen <\/b>der in <b>objRibbon <\/b>gespeicherten Instanz der Klasse <b>Ribbon_Access <\/b>auf <b>False <\/b>ein. Danach rufen wir die <b>Invalidate<\/b>-Methode der <b>ribbon<\/b>-Eigenschaft von <b>objRibbon <\/b>auf:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Async Sub HandleTimer(sender<span style=\"color:blue;\"> As Object<\/span>, _\r\n         e<span style=\"color:blue;\"> As <\/span>EventArgs)\r\n     Await Task.Run(\r\n         Sub()\r\n             <span style=\"color:blue;\">If <\/span>Application.CurrentDb Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>Loaded = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                     Loaded = <span style=\"color:blue;\">False<\/span>\r\n                     objRibbon.DatenbankGeladen = <span style=\"color:blue;\">False<\/span>\r\n                     objRibbon.ribbon.Invalidate()\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n                 ...<\/pre>\n<p>Im <b>Else<\/b>-Teil dann, wo die Datenbank geladen ist, stellen wir <b>DatenbankGeladen <\/b>auf <b>True <\/b>ein und rufen wieder die <b>Invalidate<\/b>-Methode auf:<\/p>\n<pre>             ...\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>Loaded = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                     Loaded = <span style=\"color:blue;\">True<\/span>\r\n                     objRibbon.DatenbankGeladen = <span style=\"color:blue;\">True<\/span>\r\n                     objRibbon.ribbon.Invalidate()\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         End Sub\r\n     )\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Ganze verlangt nat&uuml;rlich nun nach der Erl&auml;uterung der &auml;nderungen in der Klasse <b>Ribbon_Access<\/b>. Hier brauchen wir erstmal den Namespace f&uuml;r Access:<\/p>\n<pre>Imports Access = Microsoft.Office.Interop.Access<\/pre>\n<p>Dann ben&ouml;tigen wir statt <b>Private Ribbon As Office.IRib-bon-UI <\/b>eine private Variable des Typs <b>IRibbonUI<\/b>, die wir per <b>Property <\/b>nach au&szlig;en schreib- und lesbar machen:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>_ribbon<span style=\"color:blue;\"> As <\/span>Office.IRibbonUI\r\n<span style=\"color:blue;\">Public Property <\/span>Ribbon<span style=\"color:blue;\"> As <\/span>Office.IRibbonUI\r\n     Get\r\n         Return _ribbon\r\n     End Get\r\n     Set(value<span style=\"color:blue;\"> As <\/span>Office.IRibbonUI)\r\n         _ribbon = value\r\n     End <span style=\"color:blue;\">Set<\/span>\r\n<span style=\"color:blue;\">End Property<\/span><\/pre>\n<p>Das gleiche Konstrukt legen wir f&uuml;r die Boolean-Variable an, die den Zustand beschreibt, ob eine Datenbank geladen ist:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>_datenbankGeladen<span style=\"color:blue;\"> As Boolean<\/span>\r\n<span style=\"color:blue;\">Public Property <\/span>DatenbankGeladen()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     Get\r\n         Return _DatenbankGeladen\r\n     End Get\r\n     Set(value<span style=\"color:blue;\"> As Boolean<\/span>)\r\n         _DatenbankGeladen = value\r\n     End <span style=\"color:blue;\">Set<\/span>\r\n<span style=\"color:blue;\">End Property<\/span><\/pre>\n<p>Und schlie&szlig;lich noch eine Property f&uuml;r das <b>Access.Application<\/b>-Objekt:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>_application<span style=\"color:blue;\"> As <\/span>Access.Application\r\n<span style=\"color:blue;\">Public Property <\/span>Application<span style=\"color:blue;\"> As <\/span>Access.Application\r\n     Get\r\n         Return _application\r\n     End Get\r\n     Set(value<span style=\"color:blue;\"> As <\/span>Access.Application)\r\n         _application = value\r\n     End <span style=\"color:blue;\">Set<\/span>\r\n<span style=\"color:blue;\">End Property<\/span><\/pre>\n<p>Wegen des ge&auml;nderten Variablennamens f&uuml;r die Variable des Typs <b>IRibbonUI <\/b>m&uuml;ssen wir die Methode <b>Ribbon_Load <\/b>&auml;ndern:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>Ribbon_Load(ByVal ribbonUI<span style=\"color:blue;\"> As <\/span>Office.IRibbonUI)\r\n     _ribbon = ribbonUI\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Methode <b>GetEnabled <\/b>schlie&szlig;lich aktiviert oder deaktiviert die Schaltfl&auml;che <b>btnTabellen <\/b>in Abh&auml;ngigkeit vom Wert der privaten Variablen <b>_datenbankGeladen<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>GetEnabled(control<span style=\"color:blue;\"> As <\/span>Office.IRibbonControl) _\r\n        <span style=\"color:blue;\"> As Boolean<\/span>\r\n     Select Case control.Id\r\n         <span style=\"color:blue;\">Case <\/span>\"btnTabellen\"\r\n             GetEnabled = _datenbankGeladen\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<h2>Funktionen des Add-Ins<\/h2>\n<p>Damit kommen wir zur Implementierung der Ereignisse, die beim Anklicken der einzelnen Ribbon-Elemente ausgel&ouml;st werden. Diese finden wir in der <b>onAction<\/b>-Prozedur, die wie in Listing 3 aussieht.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>onAction(ctl<span style=\"color:blue;\"> As <\/span>Office.IRibbonControl)\r\n     <span style=\"color:blue;\">Dim <\/span>objWindow<span style=\"color:blue;\"> As <\/span>Tabellenauswahl\r\n     Select Case ctl.Id\r\n         <span style=\"color:blue;\">Case <\/span>\"btnAnwendungsbefehl\"\r\n             Ribbon.Invalidate()\r\n         <span style=\"color:blue;\">Case <\/span>\"btnNavigationsbereichEinblenden\"\r\n             _application.DoCmd.SelectObject(Access.AcObjectType.acTable, vbNullString, <span style=\"color:blue;\">True<\/span>)\r\n         <span style=\"color:blue;\">Case <\/span>\"btnNavigationsbereichAusblenden\"\r\n             _application.DoCmd.SelectObject(Access.AcObjectType.acTable, vbNullString, <span style=\"color:blue;\">True<\/span>)\r\n             _application.DoCmd.RunCommand(Access.AcCommand.acCmdWindowHide)\r\n         <span style=\"color:blue;\">Case <\/span>\"btnTabellen\"\r\n             \/\/objWindow = <span style=\"color:blue;\">New<\/span> UserControl1(_application)   ... werden sp&auml;ter erl&auml;utert!\r\n             \/\/objWindow.Show()\r\n             \/\/objWindow.Topmost = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Durch die Schaltfl&auml;chen ausgel&ouml;ste Funktionen<\/span><\/b><\/p>\n<p>Diese Prozedur pr&uuml;ft wieder, von welcher Schaltfl&auml;che sie ausgel&ouml;st wurde. Im Falle von <b>btnNavigationsbereichEinblenden <\/b>verwendet sie die &uuml;ber die Eigenschaft <b>Application <\/b>der Klasse <b>Ribbon_Access <\/b>&uuml;bergebene Referenz auf die als Host dienende Access-Anwendung. Diese ist in der lokalen Variablen <b>_application <\/b>gespeichert. &uuml;ber dieses Element k&ouml;nnen wir auf all die eingebauten Objekte von Access zugreifen, also zum Beispiel das <b>DoCmd<\/b>-Objekt.<\/p>\n<p>Dieses bietet die Methode <b>SelectObject <\/b>an, mit der wir den Navigationsbereich einblenden. Dieser Methode &uuml;bergeben wir als ersten Parameter den Typ des zu selektierenden Objekts (eine Tabelle) und als zweiten den Namen dieser Tabelle, wobei wir hier keine Tabelle explizit selektieren wollen und somit <b>vbNullString <\/b>&uuml;bergeben, was letztendlich den Navigationsbereich einblendet, ohne &uuml;berhaupt ein Objekt zu selektieren &#8211; dies alles in Ermangelung einer einfachen Methode, um den Navigationsbereich direkt einzublenden.<\/p>\n<p>Sollte der Benutzer hingegen die Schaltfl&auml;che <b>btnNavigationsbereichAusblenden <\/b>angeklickt haben, f&uuml;hrt <b>onAction <\/b>gleich zwei Anweisungen aus. Die erste selektiert genau wie bei <b>btnNavigationsbereichEinblenden <\/b>den Navigationsbereich. Die zweite ruft die Methode <b>RunCommand <\/b>auf und &uuml;bergibt dieser den Wert <b>acCmdWindowHide <\/b>als Parameter. Dadurch wird das aktuell markierte Objekt, in diesem Fall der Navigationsbereich, als versteckt markiert. Wie Bild 4 zeigt, mit gutem Erfolg!<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_004.png\" alt=\"Schaltfl&auml;che zum Ausblenden des Navigationsbereichs\" width=\"599,593\" height=\"239,5135\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Schaltfl&auml;che zum Ausblenden des Navigationsbereichs<\/span><\/b><\/p>\n<h2>Datenzugriff per Add-In<\/h2>\n<p>Damit kommen wir zum abschlie&szlig;enden Beispiel, in dem wir einen Dialog &ouml;ffnen wollen, der auf die Daten der aktuellen Datenbank zugreift. Das wollen wir in diesem Fall auf einfache Weise tun, also etwa ohne vorherige Auswahl der anzuzeigenden Tabelle. Wir w&auml;hlen daher die Tabelle <b>MSysObjects <\/b>aus und wollen die Namen aller Tabellen, die in dieser Tabelle aufgelistet werden, in einem Listenfeld anzeigen. Ein Doppelklick auf einen der Eintr&auml;ge soll dann die entsprechende Tabelle &ouml;ffnen.<\/p>\n<p>Dazu brauchen wir nat&uuml;rlich erstmal ein Benutzeroberfl&auml;chen-Element in der Art eines Formulars. Der Dialog <b>Neues Element hinzuf&uuml;gen <\/b>bietet dazu allein das Element <b>Windows Form <\/b>an. Ich arbeite aber grunds&auml;tzlich mit WPF. F&uuml;r WPF steht allerdings nur ein Element namens <b>Benutzersteuerelement (WPF) <\/b>zur Verf&uuml;gung. Dieses k&ouml;nnen wir jedoch leicht in ein Element des Typs <b>Window <\/b>umwandeln. Also f&uuml;gen wir dem Projekt ein Element dieses Typs hinzu und nennen es <b>Tabellenauswahl.xaml<\/b>. Es erscheint die Entwurfsansicht aus Bild 5. Hier k&ouml;nnen wir noch nicht einmal einen Rahmen des Elements erkennen, was aber f&uuml;r das <b>UserControl<\/b>-Element typisch ist, da es normalerweise in andere Elemente eingebettet wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_005.png\" alt=\"Anlegen einer Benutzeroberfl&auml;che\" width=\"649,559\" height=\"435,1038\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Anlegen einer Benutzeroberfl&auml;che<\/span><\/b><\/p>\n<p>WPF-Elemente werden komplett mit XML definiert. Um aus dem <b>UserControl<\/b>-Element, das wir nicht allein als Fenster anzeigen k&ouml;nnen, ein Window-Element zu machen, m&uuml;ssen wir &#8211; Sie ahnen es bereits &#8211; einfach nur den Elementnamen <b>UserControl <\/b>durch <b>Window <\/b>ersetzen. Danach sieht der Entwurf auch gleich ganz anders aus (s. Bild 6).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_006.png\" alt=\"&auml;nderung von UserControl in Window\" width=\"424,7115\" height=\"354,4145\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: &auml;nderung von UserControl in Window<\/span><\/b><\/p>\n<p>In der <b>.xaml<\/b>-Datei ersetzen Sie f&uuml;r das <b>Window<\/b>-Element nun die beiden Attribute <\/p>\n<pre>d:DesignHeight=\"300\" d:DesignWidth=\"300\"<\/pre>\n<p>durch die folgenden:<\/p>\n<pre>Height=\"300\" Width=\"300\"<\/pre>\n<p>Nun f&uuml;gen Sie aus der Toolbox ein <b>ListBox<\/b>&#8211; und ein <b>Button<\/b>-Element hinzu. F&uuml;r diese beiden Elemente f&uuml;gt Visual Studio dann entsprechende Unterelemente zum <b>Grid<\/b>-Element im <b>.xaml<\/b>-Code hinzu. Diese &auml;ndern Sie wie folgt, damit die Steuerelemente ordentlich ausgerichtet werden und die Gr&ouml;&szlig;e beim Ver&auml;ndern der Gr&ouml;&szlig;e des Fensters angepasst wird:<\/p>\n<pre>&lt;Grid&gt;\r\n     &lt;ListBox x:Name=\"lstTabellen\" HorizontalAlignment=\"Stretch\" Margin=\"10,10,10,40\" VerticalAlignment=\"Stretch\" MouseDoubleClick=\"lstTabellen_MouseDoubleClick\"\/&gt;\r\n     &lt;Button x:Name=\"btnOK\" Content=\"OK\" HorizontalAlignment=\"Left\" Margin=\"10,0,0,10\" VerticalAlignment=\"Bottom\" Width=\"75\" Click=\"btnOK_Click\"\/&gt;\r\n&lt;\/Grid&gt;<\/pre>\n<p>Die beiden Elemente enthalten jeweils eine Ereignismethode. Die des <b>ListBox<\/b>-Elements hei&szlig;t <b>lstTabellen_MouseDoubleClick <\/b>und wird durch einen Doppelklick auf einen der Eintr&auml;ge in der <b>ListBox <\/b>ausgel&ouml;st. Um diese Methode anzulegen, f&uuml;gen Sie dem <b>ListBox<\/b>-Element das Attribut <b>MouseDoubleClick <\/b>hinzu und geben noch ein Gleichheitszeichen ein. Es erscheint dann wie in Bild 7 die Auswahl <b><Neuer Ereignishandler><\/b>, die Sie mit der Tabulator-Taste oder einem Mausklick &uuml;bernehmen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_007.png\" alt=\"Hinzuf&uuml;gen einer Ereignisprozedur in Visual Studio\" width=\"499,6607\" height=\"201,786\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Hinzuf&uuml;gen einer Ereignisprozedur in Visual Studio<\/span><\/b><\/p>\n<p>Dies legt die Methode automatisch in dem Code behind-Modul an, also in der Klassendatei, in der sich die Anwendungslogik f&uuml;r dieses Element befindet. Markieren Sie den Namen der Methode im <b>.xaml<\/b>-Code und dr&uuml;cken Sie die Taste <b>F12<\/b>, um direkt zum Code zu wechseln. Sie landen dann in dem Modul aus Bild 8, wo Sie die vorbereitete Methode <b>lstTabellen_MouseDoubleClick <\/b>vorfinden. Auf die gleiche Weise legen Sie auch noch eine Methode f&uuml;r die Ereigniseigenschaft <b>Click <\/b>der Schaltfl&auml;che <b>btnOK <\/b>an. Bevor wir diese Methoden f&uuml;llen, sind allerdings noch ein paar weitere Schritte n&ouml;tig. Das Fenster soll Daten aus einer Tabelle der aktuell geladenen Datenbank anzeigen. Also brauchen wir auch Zugriff auf diese Datenbank, am besten auch gleich auf die Access-Instanz, in der diese Datenbank ge&ouml;ffnet ist. Die Access-Instanz k&ouml;nnten wir mit einer &ouml;ffentlichen Variablen in einem Standardmodul verf&uuml;gbar machen, aber das ist kein guter Programmierstil. Stattdessen wollen wir die Referenz beim Aufruf des <b>Window<\/b>-Objekts an dieses &uuml;bergeben. Das ist unter VB\/WPF wesentlich einfacher als unter Access, wo Sie mit der <b>DoCmd.OpenForm<\/b>-Methode nur unzureichende M&ouml;glichkeiten zur &uuml;bergabe von Daten haben.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_008.png\" alt=\"Anlegen einer neuen Ereignismethode f&uuml;r das ListBox-Element\" width=\"649,559\" height=\"136,3083\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Anlegen einer neuen Ereignismethode f&uuml;r das ListBox-Element<\/span><\/b><\/p>\n<h2>&ouml;ffnen des Fensters &uuml;ber die Schaltfl&auml;che des Ribbons<\/h2>\n<p>Also schauen wir uns die beiden Anweisungen aus der Ribbon-Methode <b>onAction <\/b>an, mit denen wir das <b>Window<\/b>-Objekt <b>Tabellenauswahl <\/b>erstellen und anzeigen und die wir bereits weiter oben im Listing gezeigt haben:<\/p>\n<pre>objWindow = <span style=\"color:blue;\">New<\/span> Tabellenauswahl(_application)\r\nobjWindow.Show()\r\nobjWindow.Topmost = <span style=\"color:blue;\">True<\/span><\/pre>\n<p>Die erste Anweisung instanziert das Objekt <b>Tabellenauswahl<\/b>. Die zweite blendet das Window ein, die dritte sorgt daf&uuml;r, dass dieses immer im Vordergrund bleibt. <\/p>\n<p>Dass die Instanzierung mit dem Schl&uuml;sselwort <b>New <\/b>geschieht, kennen Sie bereits von VBA. Aber hier &uuml;bergeben wir gleich noch einen Parameter an die Klasse, n&auml;mlich die Variable <b>_application <\/b>und somit einen Verweis auf die als Host dienende Access-Anwendung. Aber wo werten wir die &uuml;bergebene Variable nun aus Dies erledigen wir in einer noch zu erstellenden Methode namens <b>New<\/b>. Diese wird auch Konstruktor-Methode genannt und immer beim Erstellen des Objekts auf Basis dieser Klasse aufgerufen (s. Listing 4). Damit die Methode funktioniert, f&uuml;gen Sie der Klasse noch zwei <b>Imports<\/b>-Anweisungen hinzu:<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>New(Application<span style=\"color:blue;\"> As <\/span>Access.Application)\r\n     InitializeComponent()\r\n     _application = Application\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>Recordset\r\n     db = _application.CurrentDb\r\n     rst = db.OpenRecordset(\"SELECT * FROM MSysObjects WHERE Type = 1 AND (Name NOT LIKE ''''MSys*'''')\")\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         Me.lstTabellen.Items.Add(rst.Fields(\"Name\").Value)\r\n         rst.MoveNext()\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Die Konstruktor-Methode, die beim Initialisieren der Klasse Tabellenauswahl ausgel&ouml;st wird<\/span><\/b><\/p>\n<pre>Imports Access = Microsoft.Office.Interop.Access\r\nImports Microsoft.Office.Interop.Access.Dao<\/pre>\n<p>Die erste vergibt f&uuml;r den Namespace <b>Microsoft.Office.Interop.Access <\/b>den Alias <b>Access<\/b>. Wenn in der Methode <b>New <\/b>auf Objekte wie <b>Access.Application <\/b>zugegriffen wird, dann bezieht sich Access immer auf diesen Namespace. Das ist zum Beispiel in der folgenden Deklarationszeile der Fall:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>_application<span style=\"color:blue;\"> As <\/span>Access.Application<\/pre>\n<p>In dieser Variablen speichert die <b>New<\/b>-Methode auch gleich in der zweiten Zeile das &uuml;bergebene <b>Application<\/b>-Objekt. Danach folgen einige Zeilen, die Ihnen von Access\/VBA her bekannt vorkommen sollten. Der Unterschied ist, dass wir an manchen Stellen den Namespace-Alias <b>Access <\/b>voranstellen. Au&szlig;erdem verwendet man unter Visual Basic 2015 nicht wie unter VBA die <b>Set<\/b>-Anweisung, um Objektvariablen zu f&uuml;llen. Die Anweisungen f&uuml;llen ein <b>Recordset<\/b>-Objekt mit einem Recordset auf Basis der Tabelle <b>MSysObjects<\/b>, wobei nur die lokalen Tabellen ohne die Systemtabellen ber&uuml;cksichtigt werden. Danach durchl&auml;uft sie das Recordset in einer <b>Do While<\/b>-Schleife und f&uuml;llt die Werte des Feldes <b>Name <\/b>nacheinander als neue Eintr&auml;ge zur ListBox hinzu. Das Ergebnis sieht schlie&szlig;lich wie in Bild 9 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2017_04\/pic_1094_009.png\" alt=\"Anzeige des Fensters mit der Liste der Tabellen\" width=\"424,7115\" height=\"375,9621\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Anzeige des Fensters mit der Liste der Tabellen<\/span><\/b><\/p>\n<p>Es fehlt noch die Funktion f&uuml;r den Doppelklick auf einen der ListBox-Eintr&auml;ge sowie f&uuml;r die Schaltfl&auml;che <b>btnOK<\/b>. Diese beiden enthalten nur jeweils eine Anweisung und sehen wie in Listing 5 aus. Der Doppelklick auf einen Eintrag in der ListBox f&uuml;hrt zum Aufruf der <b>DoCmd.OpenTable<\/b>-Methode mit dem ausgew&auml;hlten Eintrag des <b>ListBox<\/b>-Elements als Parameter. Damit &ouml;ffnen Sie die angeklickte Tabelle so wie &uuml;ber den Navigationsbereich. Ein Klick auf die Schaltfl&auml;che <b>btnOK <\/b>schlie&szlig;t das Window-Objekt <b>Tabellenauswahl <\/b>mit der Methode <b>Me.Close<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>lstTabellen_MouseDoubleClick(sender<span style=\"color:blue;\"> As Object<\/span>, e<span style=\"color:blue;\"> As <\/span>System.Windows.Input.MouseButtonEventArgs)\r\n     _application.DoCmd.OpenTable(lstTabellen.SelectedValue)\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>btnOK_Click(sender<span style=\"color:blue;\"> As Object<\/span>, e<span style=\"color:blue;\"> As <\/span>System.Windows.RoutedEventArgs)\r\n     Me.Close()\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Methoden f&uuml;r die beiden Steuer-elemente des Window-Elements Tabellenauswahl<\/span><\/b><\/p>\n<h2>Auftretende Probleme<\/h2>\n<p>Mit dem hier vorgestellten Add-In hatten wir das Problem, dass fr&uuml;her oder sp&auml;ter ein Fehler auftrat, dessen Text wie folgt lautet:<\/p>\n<pre>System.Runtime.InteropServices.COMException wurde nicht behandelt.\r\nMessage: Ein Ausnahmefehler des Typs \"System.Runtime.InteropServices.COMException\" ist in mscorlib.dll aufgetreten.Zus&auml;tzliche Informationen: Mehr Datenbanken k&ouml;nnen nicht ge&ouml;ffnet werden.<\/pre>\n<p>Wo kann die Ursache liegen Neue Datenbanken werden ja nicht ge&ouml;ffnet. Aber greifen wir vielleicht in der Methode <b>HandleTimer <\/b>zu oft auf die Funktion <b>CurrentDb <\/b>zu Da es bis zum Auftreten des Fehlers oft eine Weile dauert, wollen wir &#8211; falls dies die Ursache ist &#8211; zun&auml;chst die Wartezeit bis hierhin verk&uuml;rzen und setzen die Zeit des Timers durch &auml;ndern der Initialisierung in <b>ThisAddIn_Startup <\/b>wie folgt auf eine zehntel Sekunde herunter:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>ThisAddIn_Startup() Handles Me.Startup\r\n     ...\r\n     timer = <span style=\"color:blue;\">New<\/span> System.Timers.Timer(1000)\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Der Fehler tritt nun schon nach weniger als einer Minute auf. Was k&ouml;nnen wir hier &auml;ndern Im Timer wollen wir ja daf&uuml;r sorgen, dass die Schaltfl&auml;chen, die nur in Zusammenhang mit einer geladenen Datenbank verwendet werden sollen, ansonsten deaktiviert sind. Die <b>Timer<\/b>-Funktion l&auml;uft also die ganze Zeit, auch um zu pr&uuml;fen, ob der Benutzer die Datenbank wieder schlie&szlig;t und eine neue Datenbank &ouml;ffnet, und greift dabei auch immer wieder auf <b>CurrentDb <\/b>zu, was wohl nach einer gewissen Anzahl Zugriffe zum Fehler f&uuml;hrt. Den Timer haben wir eingef&uuml;hrt, weil es kein Ereignis gibt, das ausgel&ouml;st wird, wenn der Benutzer eine Datenbank &ouml;ffnet. Also fragen wir einmal pro Sekunde nach. Das machen wir allerdings nach dem &ouml;ffnen einer Datenbank durch den Benutzer weiterhin. Aber ist das n&ouml;tig Nein! Denn zum Schlie&szlig;en der Datenbank gibt es nur einen einzigen eingebauten Ribbon-Befehl namens <b>FileCloseDatabase<\/b>. Wie wir gelernt haben, k&ouml;nnen wir eingebaute Ribbon-Befehle abfangen und durch eigene Funktionen ersetzen. Das machen wir in diesem Fall. Wir definieren also zun&auml;chst ein <b>command<\/b>-Element f&uuml;r diesen Ribbon-Befehl und legen fest, dass der Befehl von nun an eine Methode namens <b>onAction_Command <\/b>ausl&ouml;sen soll. Dies geschieht in der Datei <b>Ribbon_Access.xml<\/b>:<\/p>\n<pre>&lt;customUI xmlns=\"http:\/\/schemas.microsoft.com\/office\/2009\/07\/customui\" onLoad=\"Ribbon_Load\" loadImage=\"loadImage\"&gt;\r\n   &lt;commands&gt;\r\n     &lt;command idMso=\"FileCloseDatabase\" \r\n       onAction=\"onAction_Command\"\/&gt;\r\n   &lt;\/commands&gt;\r\n   &lt;ribbon&gt;\r\n     ...\r\n   &lt;\/ribbon&gt;\r\n&lt;\/customUI&gt;<\/pre>\n<p>Die dadurch ausgel&ouml;ste Methode definieren wir in <b>Ribbon_Access.vb <\/b>wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>onAction_Command(ctl<span style=\"color:blue;\"> As <\/span>Office.IRibbonControl, _\r\n         ByRef cancelDefault<span style=\"color:blue;\"> As Boolean<\/span>)\r\n     Select Case ctl.Id\r\n         <span style=\"color:blue;\">Case <\/span>\"FileCloseDatabase\"\r\n             RaiseEvent DatabaseClosed()\r\n             cancelDefault = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             MessageBox.Show(ctl.Id)\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Hier l&ouml;sen wir ein Event namens <b>DatabaseClosed <\/b>aus, welches wir ebenfalls in <b>Ribbon_Access.vb <\/b>definieren:<\/p>\n<pre>Event DatabaseClosed()<\/pre>\n<p>Dieses Event wollen wir nun in die Klasse <b>ThisAddIn.vb <\/b>implementieren. Dazu m&uuml;ssen wir die Objektvariable <b>obj-Ribbon <\/b>f&uuml;r die Klasse <b>Ribbon_Access <\/b>zun&auml;chst einmal um das Schl&uuml;sselwort <b>WithEvents <\/b>erweitern:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents objRibbon<span style=\"color:blue;\"> As <\/span>Ribbon_Access<\/pre>\n<p>Das nun zu implementierende Ereignis soll ja den Timer neu starten. Dazu ziehen wir die Deklaration der Objektvariablen <b>timer <\/b>aus der Methode <b>ThisAddIn_Startup <\/b>heraus und schreiben sie in den Kopf der Klasse:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>timer<span style=\"color:blue;\"> As <\/span>System.Timers.Timer<\/pre>\n<p>Damit k&ouml;nnen wir die Implementierung des Ereignisses <b>DatabaseClosed <\/b>abschlie&szlig;en und die folgende Ereignisprozedur schreiben, welche lediglich die <b>Start<\/b>-Methode des Timers aufruft:<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>objRibbon_EventHandler() Handles _\r\n         objRibbon.DatabaseClosed\r\n     timer.Start()\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Ist unsere Aufgabe damit abgeschlossen Nein, denn der Timer wird ja nach dem Laden einer Access-Datenbank noch gar nicht beendet! Die dazu n&ouml;tige Anweisung f&uuml;gen wir noch zu der Methode hinzu, die durch den Timer ausgel&ouml;st wird:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Async Sub HandleTimer(sender<span style=\"color:blue;\"> As Object<\/span>, _\r\n         e<span style=\"color:blue;\"> As <\/span>EventArgs)\r\n     Await Task.Run(\r\n         Sub()\r\n             <span style=\"color:blue;\">If <\/span>Application.CurrentDb Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>Loaded = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                     ...\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 <span style=\"color:blue;\">If <\/span>Loaded = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                     ...\r\n                     timer.Stop()\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         End Sub\r\n     )\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit l&auml;uft der Timer so lange, bis der Benutzer eine Datenbank ge&ouml;ffnet hat. Bis dahin richtet die Methode <b>HandleTimer <\/b>keinen Schaden an, denn der Aufruf von <b>CurrentDb <\/b>&ouml;ffnet ja keine Datenbank. Dies geschieht erst, wenn der Benutzer tats&auml;chlich eine Datenbank &ouml;ffnet. Dann wird der Timer aber direkt angehalten, <b>HandleTimer <\/b>greift also nicht weiter auf <b>CurrentDb <\/b>zu. Das ist erst der Fall, wenn der Benutzer die aktuell ge&ouml;ffnete Datenbank mit der Ribbon-Schaltfl&auml;che <b>File-Close-Database <\/b>schlie&szlig;t. Aber was ist, wenn der Benutzer die aktuelle Datenbank auf eine andere Art schlie&szlig;t &#8211; etwa mit <b>DoCmd.CloseDatabase<\/b> Dann greift unsere Vorgehensweise nicht mehr. Aber das ist kein Problem, denn in diesem Fall wird das Ribbon nicht mehr angezeigt &#8211; es erscheint n&auml;mlich die Seite, die immer beim Start von Access angezeigt wird und keinen Zugriff auf das Ribbon bietet.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Mit diesen Beispielen haben Sie Material, das Sie erstens direkt einsetzen und zweitens als Grundlage f&uuml;r eigene Erweiterungen nutzen k&ouml;nnen. In weiteren Beitr&auml;gen werden wir beispielsweise zeigen, wie Sie ein Setup f&uuml;r ein solches Add-In erstellen.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>AccessAddIn_VB.rar<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/B2319FCA-BB4B-44F1-AA07-8AA5C522C2D2\/aiu_1094.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Beitrag &#8222;Access-Add-In mit VSTO&#8220; haben Sie erfahren, wie Sie aus einer der bestehenden Vorlagen f&uuml;r Outlook-, Word- oder Excel-Add-Ins ein Access-Add-In zaubern. In diesem Beitrag nun wollen wir uns ansehen, wie Sie von einem solchen Add-In auf die Objekte der Datenbank und auch auf die darin enthaltenen Daten zugreifen k&ouml;nnen Damit erhalten Sie die Grundlage, viele interessante und praktische Add-Ins f&uuml;r Access zu bauen.<\/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,66042017,44000025],"tags":[],"class_list":["post-55001094","post","type-post","status-publish","format-standard","hentry","category-662017","category-66042017","category-VBA_und_Programmiertechniken"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Datenzugriff per VSTO-Add-In - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Datenzugriff per VSTO-Add-In\" \/>\n<meta property=\"og:description\" content=\"Im Beitrag &quot;Access-Add-In mit VSTO&quot; haben Sie erfahren, wie Sie aus einer der bestehenden Vorlagen f&uuml;r Outlook-, Word- oder Excel-Add-Ins ein Access-Add-In zaubern. In diesem Beitrag nun wollen wir uns ansehen, wie Sie von einem solchen Add-In auf die Objekte der Datenbank und auch auf die darin enthaltenen Daten zugreifen k&ouml;nnen Damit erhalten Sie die Grundlage, viele interessante und praktische Add-Ins f&uuml;r Access zu bauen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T21:26:12+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg09.met.vgwort.de\/na\/99aed82cac1842099e731307ceca73a3\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"26\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Datenzugriff per VSTO-Add-In\",\"datePublished\":\"2020-05-13T21:26:12+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/\"},\"wordCount\":4403,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/99aed82cac1842099e731307ceca73a3\",\"articleSection\":[\"2017\",\"4\\\/2017\",\"VBA und Programmiertechniken\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/\",\"name\":\"Datenzugriff per VSTO-Add-In - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/99aed82cac1842099e731307ceca73a3\",\"datePublished\":\"2020-05-13T21:26:12+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/99aed82cac1842099e731307ceca73a3\",\"contentUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/99aed82cac1842099e731307ceca73a3\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenzugriff_per_VSTOAddIn\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Datenzugriff per VSTO-Add-In\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Datenzugriff per VSTO-Add-In - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/","og_locale":"de_DE","og_type":"article","og_title":"Datenzugriff per VSTO-Add-In","og_description":"Im Beitrag \"Access-Add-In mit VSTO\" haben Sie erfahren, wie Sie aus einer der bestehenden Vorlagen f&uuml;r Outlook-, Word- oder Excel-Add-Ins ein Access-Add-In zaubern. In diesem Beitrag nun wollen wir uns ansehen, wie Sie von einem solchen Add-In auf die Objekte der Datenbank und auch auf die darin enthaltenen Daten zugreifen k&ouml;nnen Damit erhalten Sie die Grundlage, viele interessante und praktische Add-Ins f&uuml;r Access zu bauen.","og_url":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T21:26:12+00:00","og_image":[{"url":"http:\/\/vg09.met.vgwort.de\/na\/99aed82cac1842099e731307ceca73a3","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"26\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Datenzugriff per VSTO-Add-In","datePublished":"2020-05-13T21:26:12+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/"},"wordCount":4403,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#primaryimage"},"thumbnailUrl":"http:\/\/vg09.met.vgwort.de\/na\/99aed82cac1842099e731307ceca73a3","articleSection":["2017","4\/2017","VBA und Programmiertechniken"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/","url":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/","name":"Datenzugriff per VSTO-Add-In - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#primaryimage"},"thumbnailUrl":"http:\/\/vg09.met.vgwort.de\/na\/99aed82cac1842099e731307ceca73a3","datePublished":"2020-05-13T21:26:12+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#primaryimage","url":"http:\/\/vg09.met.vgwort.de\/na\/99aed82cac1842099e731307ceca73a3","contentUrl":"http:\/\/vg09.met.vgwort.de\/na\/99aed82cac1842099e731307ceca73a3"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Datenzugriff_per_VSTOAddIn\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Datenzugriff per VSTO-Add-In"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001094","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001094"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001094\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001094"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001094"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001094"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}