Fehler in asynchronem CommonOpenFileDialog | Invoke()-Aufruf falsch?

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Fehler in asynchronem CommonOpenFileDialog | Invoke()-Aufruf falsch?

    Hallo zusammen,
    wenn ich in VB.NET einen CommonOpenFileDialog in einer asynchronen Prozedur stehen habe, muss ich bekanntlich so etwas tun:

    VB.NET-Quellcode

    1. Dim Pfad As String
    2. Using OFD1 As New CommonOpenFileDialog
    3. OFD1.Title = "Exceldatei auswählen"
    4. OFD1.Filters.Add(New CommonFileDialogFilter("Excel", ".xlsx, .xls"))
    5. If System.IO.Directory.Exists("C:\Users\Name\source\repos\VB.NET\bla") Then
    6. OFD1.InitialDirectory = "C:\Users\Name\source\repos\VB.NET\bla"
    7. Else
    8. OFD1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    9. End If
    10. Dim Result As CommonFileDialogResult
    11. Me.Invoke(Sub() Result = OFD1.ShowDialog())
    12. If Result = CommonFileDialogResult.Ok Then
    13. Pfad = OFD1.FileName
    14. Else
    15. Return
    16. End If
    17. End Using

    also Result wird separat gespeichert, anstatt, wie in einer synchronen Prozedur möglich, direkt If OFD1.ShowDialog = CommonFileDialogResult.Ok Then zu schreiben.

    Nach C# übertragen wird das nicht akzeptiert. Was mache ich falsch? Ich denke, der Aufruf in Invoke ist falsch?!

    C#-Quellcode

    1. string FullFileName;
    2. using (CommonOpenFileDialog OFD = new CommonOpenFileDialog())
    3. {
    4. OFD.Title = "Textdatei mit Datenbank-Informationen öffnen";
    5. OFD.Filters.Add(new CommonFileDialogFilter("Textdatei", ".txt"));
    6. if (System.IO.Directory.Exists(@"C:\Users\Name\xyz"))
    7. OFD.InitialDirectory = @"C:\Users\Name\xyz";
    8. else
    9. {
    10. OFD.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
    11. }
    12. CommonFileDialogResult Result;
    13. this.Invoke(new Action(() => Result = OFD.ShowDialog()));
    14. if (Result == CommonFileDialogResult.Ok)
    15. FullFileName = OFD.FileName;
    16. else
    17. return;
    18. }


    Bartosz schrieb:

    wenn ich in VB.NET einen CommonOpenFileDialog in einer asynchronen Prozedur stehen habe, muss ich bekanntlich so etwas tun
    nein, tät ich nicht sagen.
    imo ist schon gar keine gute idee, überhaupt einen Dialog in einer asynchronen Prozedur stehen zu haben.
    Das gilt also auch für CommonOpenFileDialog - obwohl ich diesen Dialgog überhaupt nicht kenne.

    Aber ich sehe hier überhaupt keine asynchrone Procedure.
    Tatsächlich sehe hier überhaupt keine Procedure - nur ein paar verlorene Zeilen.


    Hallo ErfinderDesRades. Schön, dass du so schnell da bist!

    obwohl ich diesen Dialgog überhaupt nicht kenne.
    Im Visual-Studio-eigenen NuGet-Paket-Manager kann man hiernach suchen Microsoft.WindowsAPICodePack.Dialogs und sich das herunterladen. Ist moderner als der Dialog aus der Toolbox.

    Ich habe den Dialog in der asynchronen Prozedur stehen, da ich sie nur beim Programmstart brauche. Also auf - klicken, Prozedur einklappen, fertig.

    Bartosz schrieb:

    Schön, dass du so schnell da bist!
    Wie es der Zufall will ;)

    Den CommonOpenFileDialog kenne ich also tatsächlich nicht, und ich werde mir das Nuget-Package auch nicht installieren.
    WieDemAuchSei - es bleibt dabei:

    ErfinderDesRades schrieb:

    Aber ich sehe hier überhaupt keine asynchrone Procedure.
    Tatsächlich sehe hier überhaupt keine Procedure - nur ein paar verlorene Zeilen.

    Aufruf mittels await Task.Run(() => read_in_data());

    C#-Quellcode

    1. private void read_in_data()
    2. {
    3. string FullFileName;
    4. using (CommonOpenFileDialog OFD = new CommonOpenFileDialog())
    5. {
    6. OFD.Title = "Textdatei mit Datenbank-Informationen öffnen";
    7. OFD.Filters.Add(new CommonFileDialogFilter("Textdatei", ".txt"));
    8. if (System.IO.Directory.Exists(@"C:\Users\Name\Bla"))
    9. {
    10. OFD.InitialDirectory = @"C:\Users\Name\Bla";
    11. }
    12. else
    13. {
    14. OFD.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
    15. }
    16. CommonFileDialogResult Result;
    17. this.Invoke((Action)(() =>
    18. {
    19. Result = OFD.ShowDialog();
    20. if (Result == CommonFileDialogResult.Ok)
    21. {
    22. FullFileName = OFD.FileName;
    23. }
    24. else
    25. {
    26. return;
    27. }
    28. }));
    29. } // using (CommonOpenFileDialog OFD
    30. string[] RAT = System.IO.File.ReadAllLines(FullFileName, Encoding.UTF8);
    31. if (RAT.Length == 0 || RAT.Length == 1)
    32. {
    33. MessageBox.Show($"Die Datei\n»{FullFileName}«\nenthält nur 0 oder 1 Zeichen.",
    34. "Datenbank – Daten laden",
    35. MessageBoxButtons.OK,
    36. MessageBoxIcon.Hand);
    37. return;
    38. }
    39. for (int i = 3; i < RAT.Length - 2; i++)
    40. {
    41. }
    42. } // async


    Mit der neuen Syntax bin ich den Fehler los:
    Verwendung der nicht zugewiesenen lokalen Variablen "Result"
    dafür aber wird nun gesagt
    Verwendung der nicht zugewiesenen lokalen Variablen "FullFileName"

    Für FullFileName ist für den Compiler nicht sichergestellt, dass zwischen Deklaration und Verwendung mit ReadAllLines ein Wert zugewiesen wurde, daher die Meckerei.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed Den Artikel habe ich erst auch gesehen und dann verworfen. Tatsächlich steht darin – auskommentiert :rolleyes: – die Lösung. Erst einmal null zuweisen.
    string FullFileName = null;



    Gerade ausprobiert und funktioniert :)

    @ErfinderDesRades Ich möchte, dass diese Prozedur asynchron ist, da das Laden länger dauern könnte; über 10 Sekunden.

    Bartosz schrieb:

    Ok, aber warum geht's in VB.net?
    VB ist in einigen Sachen viel weniger restriktiv als C#, das ist Microsoft-Philosophie, Hilfe für Anfänger oder so.
    Im Prinzip wird jede Variable in .NET mit ihrem default() belegt, das ist wie auch immer der Null-Value.
    C# will aber, dass Du genau weißt, dass da Dein Wert zugewiesen ist, auch wenn der tatsächlich der Null-Value ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Bartosz: Achsooo. Ich dachte, dass Du die = null-Lösung schon von Anfang an kennst und Dir nur nicht klar war, warum der Compiler nicht erkennt, dass auch alle Pfade im Task zu einem FullFileName-Ergebnis führen, wenn es beim ReadAllText ankommt.

    ErfinderDesRades schrieb:

    (Klar dauert ein OFD.ShowDialog lange - nämlich genau so lange, wie der User braucht, um drin rumzuklicksen.
    Aber das gehört nicht async.)
    Ich geh davon aus, dass nicht nur das Dialog-Anzeigen, sondern eben das Dateiinhalt-Laden lange dauert. Aber das wäre auch kein Argument, das Ganze asynchron zu gestalten. Schließlich sollte dann eben nur das Dateiinhaltladen asynchron gestaltet werden und nicht der ganze Dialogkram drumrum.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    Joa, ich weiß, ist Bad Practice, einen Dialog in einer Async-Prozedur stehen zu haben. Aber ich denke, da ich diese Prozedur nur 1× aufgerufen wird...

    Nochmal zu den Deklarationen. Ich wusste zwar, "dass in VB.NET ein default-Wert zugewiesen wird und in C# nicht", aber ich habe mich schon gewundert, warum der C#-Compiler meckert, obwohl (im Task) etwas auf die Variable geschrieben wird. Ich dachte, der Complier meckert wegen des threadübergreifenden Aufrufs. ("2 verschiedene Threads schreiben und lesen eine Variable und das könnte schiefgehen").

    Bartosz schrieb:

    Aber ich denke, da ich diese Prozedur nur 1× aufgerufen wird...
    Ich wär jetzt schon daran interessiert, wie es nach den weitergeht. Das ist m.E. nicht das 1. Mal, dass Du einen Dialog asynchron aufrufst. Da gab's mindestens einen anderen Thread von Dir dazu. Und es scheint, als ob sich nicht nur mir nicht erschließt, welchen Vorteil Du siehst. Der Dialog ist ja anscheinend nicht der Zeitfresser.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    :huh: Aber das ist doch nur ein Visual Studio Feature. Die Frage ist doch: Was bringt Dir das Konstrukt vom Programmablauf? Das ist doch das einzig wichtige. Ich benutz diese Ein-/Ausklappfunktionalität nie. Genauso Regions. Aber das ist wurscht. Nur: Ein Codekonstrukt zusammenzubasteln, was ablauftechnisch komplex ist, nur damit man es in VS ausblenden kann, halte ich für die falsche Motivation.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Wenn Du diesen Bereich ausblenden willst, in dem der Dialog und das asynchrone Dateiladen sinch befinden, dann wär wohl tatsächlich eine Region am zielführendsten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed Jou und Nicht Jou.
    @Bartosz Wenn Du tatsächlich den Aufruf zusammen klappen willst, kannst Du entweder den kompletten Aufruf synchron in eine Prozedur packen und Du hast den Aufruf in einer Zeile
    oder
    Du machst um den Aufruf eine #Region, die kannst Du dann zu einem Einzeiler zusammen klappen.
    Code-Teile als solche zusammen zu klappen finde ich auch nicht gut.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!