Mit C# accdb Datenbank und ein bestimmtes Formular zu öffnen

  • C#

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von Mono.

    Mein Code, welchen ich aufsplitten möchte, sieht folgendermaßen aus:

    C#-Quellcode

    1. public static void openAccess()
    2. {
    3. Microsoft.Office.Interop.Access.Application oAccess = null;
    4. oAccess = new Microsoft.Office.Interop.Access.Application();
    5. oAccess.Visible = true; // auf visible setzen damit du auch siehst das es tatsächlich passiert ;)
    6. oAccess.OpenCurrentDatabase("C:\\Users\\sf\\Desktop\\MeinTest.accdb", true); // DB Pfad
    7. oAccess.DoCmd.OpenForm("MSB", // Formname
    8. Microsoft.Office.Interop.Access.AcFormView.acNormal, // View
    9. System.Reflection.Missing.Value, // FilterName
    10. "[Ku_Nr]=" + "'" + kundennr +"'", // Where Condition
    11. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormPropertySettings, // DataMode -> Im alten VB Code war es auch PropertySettings.
    12. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, // WindowMode
    13. System.Reflection.Missing.Value); // OpenArgs
    14. }


    Und so hatte ich gedacht:

    C#-Quellcode

    1. public static void openAccess()
    2. {
    3. Microsoft.Office.Interop.Access.Application oAccess = null;
    4. oAccess = new Microsoft.Office.Interop.Access.Application();
    5. oAccess.Visible = true; // auf visible setzen damit du auch siehst das es tatsächlich passiert ;)
    6. oAccess.OpenCurrentDatabase("C:\\Users\\sf\\Desktop\\MeinTest.accdb", true); // DB Pfad
    7. }
    8. public static void openForm()
    9. {
    10. oAccess.DoCmd.OpenForm("MSB", // Formname
    11. Microsoft.Office.Interop.Access.AcFormView.acNormal, // View
    12. System.Reflection.Missing.Value, // FilterName
    13. "[Ku_Nr]=" + "'" + kundennr + "'", // Where Condition
    14. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormPropertySettings, // DataMode -> Im alten VB Code war es auch PropertySettings.
    15. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, // WindowMode
    16. System.Reflection.Missing.Value); // OpenArgs
    17. }
    so wäre oAccess ausgelagert als Klassenvariable:

    C#-Quellcode

    1. private static Microsoft.Office.Interop.Access.Application oAccess = null;
    2. public static void openAccess() {
    3. oAccess = new Microsoft.Office.Interop.Access.Application();
    4. oAccess.Visible = true; // auf visible setzen damit du auch siehst das es tatsächlich passiert ;)
    5. oAccess.OpenCurrentDatabase("C:\\Users\\sf\\Desktop\\MeinTest.accdb", true); // DB Pfad
    6. }
    7. public static void openForm() {
    8. oAccess.DoCmd.OpenForm("MSB", // Formname
    9. Microsoft.Office.Interop.Access.AcFormView.acNormal, // View
    10. System.Reflection.Missing.Value, // FilterName
    11. "[Ku_Nr]=" + "'" + kundennr + "'", // Where Condition
    12. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormPropertySettings, // DataMode -> Im alten VB Code war es auch PropertySettings.
    13. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, // WindowMode
    14. System.Reflection.Missing.Value); // OpenArgs
    15. }
    Danke! Hat auf Anhieb funktioniert! Was ist eigentlich der Unterschied zwischen der Klassenvariable und dem Übergeben als Parameter? Hat bei der Klassenvariable jede Methode die Möglichkeit auf die Klassenvariable zu zugreifen und bei dem Übergeben als Parameter nur die jeweilige Methode?

    Da ich nicht nur stumpf, sondern mit Sinn programmieren möchte, so baue ich verschiedene try-catch Fälle ein. Hierbei ist es mir aufgefallen, dass die folgenden Exceptions (DirectoryNotFoundException und FileNotFoundException) in meinem Programm nicht existieren. Durch das Hinzufügen von "using System.IO;" gibt es diese Exceptions jetzt.

    Mein Code sieht nun folgendermaßen aus:

    C#-Quellcode

    1. public static void openAccess()
    2. {
    3. try
    4. {
    5. oAccess = new Microsoft.Office.Interop.Access.Application();
    6. oAccess.Visible = true; // auf visible setzen damit du auch siehst das es tatsächlich passiert ;)
    7. oAccess.OpenCurrentDatabase("C:\\Users\\sf\\Desktop\\MeinTest\\MeinTest.accdb", true); // DB Pfad
    8. }
    9. catch(DirectoryNotFoundException ex)
    10. {
    11. Console.WriteLine("Das Verzeichnis existiert nicht." + ex.Message);
    12. Console.ReadLine();
    13. }
    14. catch(FileNotFoundException ex)
    15. {
    16. Console.WriteLine("Die Datei existiert nicht." + ex.Message);
    17. Console.ReadLine();
    18. }
    19. catch(Exception ex)
    20. {
    21. Console.WriteLine("Test" + ex.Message);
    22. Console.ReadLine();
    23. }
    24. }


    Bei dem Directory habe ich zusätzlich einen Ordner hinzugefügt, welcher gar nicht existiert. Somit wollte ich mir die Fehlermeldung anzeigen lassen, welche da kommen sollte. Dasselbe Spiel soll es auch mit fehlenden Dateien passieren (FileNotFoundException). Und zum Schluss sollte noch eine "Allgemeine" Exception raus gehen, sofern die anderen Exceptions nicht gegriffen haben.
    Bei dem Ausführen des Programms wird aber nur die letzte Exception ausgeführt, obwohl das Directory gar nicht erst vorhanden ist. Was muss ich ändern, damit es funktioniert?

    Meza100 schrieb:

    Was ist eigentlich der Unterschied zwischen der Klassenvariable und dem Übergeben als Parameter?
    na, was ein parameter ist, wirste doch wissen. Sähe zB so aus:

    C#-Quellcode

    1. public static void openForm(Microsoft.Office.Interop.Access.Application oAccess) {
    2. oAccess.DoCmd.OpenForm("MSB", // Formname
    3. Microsoft.Office.Interop.Access.AcFormView.acNormal, // View
    4. System.Reflection.Missing.Value, // FilterName
    5. "[Ku_Nr]=" + "'" + kundennr + "'", // Where Condition
    6. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormPropertySettings, // DataMode -> Im alten VB Code war es auch PropertySettings.
    7. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, // WindowMode
    8. System.Reflection.Missing.Value); // OpenArgs
    9. }
    Das ist eiglich schöner, denn je mehr Klassenvariablen herumfliegen, desto schneller ergeben sich unerfreuliche SEiteneffekte. Etwa wenn du OpenForm() aufrufst, aber zuvor noch garnet OpenAccess() aufgerufen hast, gibts einen Fehler, denn oAccess ist ja noch garnet bereit, ein Form zu öffnen.
    Bei mit Parametern kann das kaum passieren, nur musst du dann halt immer ein oAccess haben, sonst kannsts ja OpenForm nicht aufrufen. Und da du vmtl. mehrmals ein Form öffnen willst - immer mit derselben AccessDb, ists sinnvoll die als Klassenvariable zu designen, weil ständig neue oAccesses zu erstellen ist eine irre performance-lastig - wenn das installierte Access da ühaupt mitspielt.



    Mir ist aufgefallen, ganz schrecklich ist die variable kundennr in deim Code. Das ist offenbar so ein Fall einer in der Klasse herumfliegenden Klassenvariable. Die sollte unbedingt paramtrisiert werden.



    zu deinen TryCatch-Übungen: Lass es erstmal. Exceptions sind nicht zum Fangen da, sondern um zu fliegen. Den Inhalt deiner selbstgebastelten Meldungen bekommst du ebenso, ja viel besser gemeldet, wenn du es lässt. Lass die Exceptions ihren Job machen, sie machen ihn gut. Catch dir das nicht selbst weg, jedenfalls nicht, ohne ein ausgefeiltes Gesamt-Konzept deiner Anwendung.
    Und es ist ausgeschlossen, dass beim derzeitigen Stand der Entwicklung, das Gesamtkonzept bereits genügend ausgereift ist, dass eine sinnvolle Fehlerbehandlung überhaupt möglich wäre.
    Eine sinnlose Fehlerbehandlung - wie man hier sieht - ist natürlich immer möglich.
    Aber sinnlos == schädlich. TryCatch ist ein heißes Eisen



    Sorry - das war nicht exakt die Antwort auf deine Frage.
    Die Exakte Antwort ist: Es wird keine DirectoryNotFoundException gefangen, weil offensichtlich keine fliegt. Was weiß ich denn, welche Exception dieses oAccess-Dingens wirft?
    Kannste rausfinden, auf 2 wegen.
    Den ersten, einfachsten, sichersten, nannte ich schon: lass den Trycatch weg. Dann wirst du sehen, welche Exception fliegt.
    Der zweite wäre ein Haltepunkt, und dann guck halt im Lokal-Fenster.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Lass das letzte Catch weg und du siehst, welche Exception eigentlich kommt.
    Bezüglich der Sichtbarkeit von Variablen..
    Es gibt sozusagen 2 Arten. Globale und lokale Variable. Jede in einer Methode oder gar innerhalb einer If Verzweigung deklarierte! Variable ist auch nur dort gültig. Nach Verlassen der Methode oder des Kontexts ist Sie nicht mehr gültig. Globale Variablen sind in der Klasse direkt deklariert und global in der Klasse gültig. Zusätzlich gibt es bei den globalen Variablen noch den Zugriffsmodifizierer, welcher festlegt, von wo aus die Variable sichtbar ist bzw. von woaus zugegriffen werden darf. Meistens entscheidet man nur zwischen Public (auch von außerhalb der Klasse sichtbar) und Private. Daneben gibt es noch internal und protected.

    C#-Quellcode

    1. class program {
    2. //Als Beispiel
    3. private int l;
    4. static int main(string[] args) {
    5. if (true)
    6. {
    7. int i;
    8. i = 1;
    9. l=2;// l ist überall verfügbar
    10. }
    11. int j = 2;
    12. int k = j + i; // i ist nicht vorhanden hier und der Kompiler meckert auch.
    13. int k = j+l; // l ist überall verfügbar
    14. }
    15. }



    //Edit:

    Eine Anmerkung noch zu globalen Variablen. Die Deklaration ist nicht gleich Initialisierung.

    C#-Quellcode

    1. public class bla
    2. int i;
    3. void somemethode(int j) {
    4. int k;
    5. k = i + j; // i kann hier null sein, also nicht mal initialisiert!
    6. }
    7. }
    8. //Man kann aber auch deklarieren und initialisieren direkt in der klasse:
    9. class bla
    10. int i = 0; //Quasi default wert


    Allerdings sollte man wie bereits von EDR erwähnt mit globalen Variablen vorsichtig sein und immer schauen, dass Sie auch im Konstruktor oder direkt initialisiert werden.
    Das ist meine Signatur und sie wird wunderbar sein!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Mono“ ()

    @ErfinderDesRades: Danke für die Erläuterung von den Klassenvariablen und Parametern, besonders auch die Vor- und Nachteile. In meinem Fall soll eigentlich nur einmal dieses Form geöffnet werden, aber danach sollte man weiterhin mit der Datenbank arbeiten können. Aus diesem Grund (und gerade wegen deiner Erklärung ;) ) werde ich wohl bei der Klassenvariable (zumindest bei oAccess) bleiben.

    Ich versuche gerade die Klassenvariable kundennr zu paramtrisieren (ich nehme mal an, die Klassenvariable raus zu nehmen und den Wert als Parameter zu übergeben?). Leider funktioniert das auch noch nicht so richtig. Code kommt gleich, doch zuerst wollte ich noch auf deine anderen Zeilen antworten.

    Dein Link zu dem Try-catch werde ich auf jeden Fall aufmerksam durchlesen. Bis ich das komplett durchgelesen habe, lasse ich erstmal die Try-Catch Blöcke noch drin.

    Code:

    Spoiler anzeigen

    C#-Quellcode

    1. // public static string kundennr;
    2. private static Microsoft.Office.Interop.Access.Application oAccess = null;
    3. public static string userName = Environment.UserName;
    4. static void Main(string[] args)
    5. {
    6. try
    7. {
    8. if (args.Length == 0) // Hat Environment.CommandLine 0 Zeichen?
    9. {
    10. keineKundennr(); // Falls ja, so wird die Methode "keineKundennr" aufgerufen.
    11. }
    12. else // Falls nein, so gibt es eine Kundennr.
    13. {
    14. ermittleUsernamen();
    15. Console.WriteLine(Environment.CommandLine); // Schreibe in die Commandline den Inhalt von Environment.Commandline.
    16. Console.ReadLine();
    17. splittenCommandLine();
    18. openAccess();
    19. openForm();
    20. }
    21. }
    22. catch (Exception ex) // Fehler (Kundennr kleiner 0) wird abgefangen.
    23. {
    24. Console.WriteLine(ex.Message);
    25. Console.WriteLine("Die Länge der Kundennummer ist unter 0");
    26. Console.ReadLine();
    27. }
    28. }
    29. private static void ermittleUsernamen()
    30. {
    31. Console.WriteLine("Mein Benutzername ist " + userName);
    32. }
    33. private static void keineKundennr()
    34. {
    35. try
    36. {
    37. string myMeldung = "Die Kommandozeile ist leer.";
    38. string appName = AppDomain.CurrentDomain.FriendlyName;
    39. Console.WriteLine("{0}{1}{1}{2}{1}Es wird eine Kundennummer benötigt.", appName, Environment.NewLine, myMeldung);
    40. Console.ReadLine();
    41. }
    42. catch (Exception ex)
    43. {
    44. Console.WriteLine(ex.Message);
    45. Console.ReadLine();
    46. }
    47. }
    48. public static void splittenCommandLine()
    49. {
    50. try
    51. {
    52. string commandLine = Environment.CommandLine;
    53. string substringAbBindestrich = commandLine.Substring(commandLine.LastIndexOf('-') + 1); // Der String wird nach dem Bindestrich aufgetrennt.
    54. string kundennr = substringAbBindestrich.Substring(substringAbBindestrich.LastIndexOf(':') + 1); // Der String wird nach dem Doppelpunkt aufgetrennt.
    55. }
    56. catch (ArgumentException ex)
    57. {
    58. Console.WriteLine(ex.Message);
    59. Console.ReadLine();
    60. }
    61. }
    62. public static void openAccess()
    63. {
    64. try
    65. {
    66. oAccess = new Microsoft.Office.Interop.Access.Application();
    67. oAccess.Visible = true; // auf visible setzen damit du auch siehst das es tatsächlich passiert ;)
    68. oAccess.OpenCurrentDatabase("C:\\Users\\" + userName + "\\Desktop\\MeinTest.accdb", true); // DB Pfad
    69. }
    70. catch (DirectoryNotFoundException ex)
    71. {
    72. Console.WriteLine("Das Verzeichnis existiert nicht." + ex.Message);
    73. Console.ReadLine();
    74. }
    75. catch(FileNotFoundException ex)
    76. {
    77. Console.WriteLine("Die Datei existiert nicht." + ex.Message);
    78. Console.ReadLine();
    79. }
    80. catch(Exception ex)
    81. {
    82. Console.WriteLine("Test" + ex.Message);
    83. Console.ReadLine();
    84. }
    85. }
    86. public static void openForm(string kundennr)
    87. {
    88. try
    89. {
    90. oAccess.DoCmd.OpenForm("MSB", // Formname
    91. Microsoft.Office.Interop.Access.AcFormView.acNormal, // View
    92. System.Reflection.Missing.Value, // FilterName
    93. "[Ku_Nr]=" + "'" + kundennr + "'", // Where Condition
    94. Microsoft.Office.Interop.Access.AcFormOpenDataMode.acFormPropertySettings, // DataMode -> Im alten VB Code war es auch PropertySettings.
    95. Microsoft.Office.Interop.Access.AcWindowMode.acWindowNormal, // WindowMode
    96. System.Reflection.Missing.Value); // OpenArgs
    97. }
    98. catch(ApplicationException ex)
    99. {
    100. Console.WriteLine(ex.Message);
    101. Console.ReadLine();
    102. }
    103. }


    @Mono: Danke! Und wie ist es, wenn ich von einer Methode auf eine lokale Variable (von einer anderen Methode) zugreifen möchte? Gibt es da andere Möglichkeiten anstelle die lokale Variable zu einer Globalen zu machen?

    Zitate entfernt. Langen Code in Spoiler verpackt. ~Thunderbolt

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thunderbolt“ ()

    Direkt zugreifen geht nicht. Man kann aber aus einer Methode eine andere aufrufen, zu dem Zeitpunkt ist die lokale Variable ja gültig und diese als Parameter übergeben:

    C#-Quellcode

    1. void something() {
    2. int j;
    3. int i = 3;
    4. j = dosomethingwithi(i); //i an die 2. methode als parameter übergeben
    5. //j ist also 6 und i 3
    6. changei(ref i);
    7. // jetzt ist i 4
    8. }
    9. int dosomethingwithi(int i) { // der parameter muss nicht i heißen !
    10. i = i +3; //tu was mit dem i (im beispiel 3 aus something)
    11. // auf die Art kann dosomethingwithi aber i aus something nicht verändern. Es wird nur der Wert übergeben.
    12. // die ursprüngliche Variable aus something bleibt unverändert!!
    13. return i; //gib die berrechneten werte zurück
    14. }
    15. //Hier per Referenz. Jetzt kann man in changei das i welches übergeben wird auch verändern
    16. void changei(ref int i) {
    17. i++; // 1 zu i dazu addieren
    18. }
    Das ist meine Signatur und sie wird wunderbar sein!
    Ah, jetzt hab ichs verstanden! Wenn ich aber den Parameter zu einer anderen Methode übergebe, so kann die Methode zwar den Parameter aufrufen, aber nicht verändern oder?

    BTW: Ich habe doch schon die try-catch Fälle gelöscht. Jedoch hätte ich noch eine Frage:

    Ich habe bisher nur den Fall behandelt, wenn Access nicht gestartet und die Datenbank zu ist. Sobald ich vor dem Starten meines Programmes Access öffne, aber die Datenbank zu habe, so startet er eine 2. Access Instanz und öffnet dort die DB. Das möchte ich nicht. Reicht es in diesem Fall einfach nach dem Process "MSACCESS" zu suchen und falls diese bereits existiert, dass er den Schritt überspringt?

    Jetzt wird es aber noch kniffliger. Falls ich Acces gestartet und die DB offen habe, so hängt sich später mein Programm auf (ich nehme mal an, dass es nur ein Zugriff geben kann?). Wie kann ich das Aufhängen verhindern, wenn Access gestartet und die DB offen ist? Da muss er doch erstmal checken, ob Access gestartet wurde, ob die DB offen ist und dann muss er nur das Form öffnen.

    Die springende Frage ist also, wie heißen die Methoden um dies zu überprüfen? Bei der Überprüfung von einem Access Prozess müsste es Process.GetProcesses heißen oder?
    schau mal hier nach.
    blogs.msdn.com/b/andreww/archi…cting-to-office-apps.aspx

    Mit Marshall.GetActiveObject sollte es gehen dich an eine aktive Access Instanz zu hängen. Du erhältst dann dein Access Object und dort kannst du dann prüfen ob die Datenbank geöffnet ist oder nicht.
    Das ist meine Signatur und sie wird wunderbar sein!