AnwendungsFramework deaktivieren

    • VB.NET

    Es gibt 2 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

      AnwendungsFramework deaktivieren

      Vb.Net beglückt uns ja standardmäßig mit dem "AnwendungsFramework". Wenn aktiviert, kann man in den Projekteinstellungen das MainForm festlegen, oder dass die Settings nicht abspeichern, oder einen SplashScreen (auf dem man aber keine wechselnden Nachrichten anzeigen kann), oder man kann die Anwendung als Einzel-Anwendung festlegen - derlei Sachen.
      Größter Nachteil des AFW ist, dass -wenn aktiv - der Debugger Exceptions nicht richtig debuggt, im Falle sie auftreten, bevor das Form anzeigt (also bis zum Form_Shown-Event) (Klingt nach exotischen SonderFällen, ist aber bei anspruchsvollen Oberflächen, und/oder bei Laden nennenswerter Datenbestände vergleichsweise unexotisch (knowWhatIMean? ;) )).

      Man kann das AFW aber auch deaktivieren:
      . . .
      Dann muss man aber ein Extra-Modul coden, mit einer Shared Sub Main, und die als StartObjekt festlegen.
      Und darin muss man alles coden, was bislang das AFW für uns getan hat - was recht betrachtet nicht sonderlich viel ist:

      VB.NET-Quellcode

      1. Public Module Program
      2. <STAThread> _
      3. Public Sub Main()
      4. Application.EnableVisualStyles()
      5. Application.SetCompatibleTextRenderingDefault(False)
      6. Application.Run(New Form1)
      7. My.Settings.Save()
      8. End Sub
      9. End Module
      (Das reicht im Normalfall - nun folgen "Extras")

      Login mit Auswahl des MainForms
      Hat man auf diese Weise selbst die Kontrolle über den Anwendungs-Startup übernommen, tun sich einem weitere Möglichkeiten auf.
      Etwa das Vorschalten eines AnmeldeDialogs ist nun viel intuitiver zu implementieren, und - was mit AFW überhaupt nicht ginge - die Anmeldung kann nun sogar darüber entscheiden, welches Form überhaupt MainForm der Anwendung wird!

      VB.NET-Quellcode

      1. Public Module Program
      2. <STAThread> _
      3. Public Sub Main()
      4. Application.EnableVisualStyles()
      5. Application.SetCompatibleTextRenderingDefault(False)
      6. Dim frm As Form = Nothing
      7. Dim selected = MessageBox.Show("Möchten Sie frmYes als MainForm, frmNo, oder wollen Sie gleich Canceln?", "Anmeldung", MessageBoxButtons.YesNoCancel)
      8. Select Case selected
      9. Case DialogResult.Yes : frm = New frmYes
      10. Case DialogResult.No : frm = New frmNo
      11. Case DialogResult.Cancel : Return
      12. Case Else : Throw New ArgumentException("unknown User-Selection")
      13. End Select
      14. Application.Run(frm)
      15. My.Settings.Save()
      16. End Sub
      17. End Module
      Hier gilt die Messagebox als Anmelde-Dialog, und frmYes / frmNo sind die beiden Optionen, mit welchem Form die Anwendung startet. Beachte auch die 3.Option: Cancel - garnicht starten.
      (Statt der MessageBox könnte es auch eine Passwort-Abfrage sein, und ein frmUser, frmAdmin würde starten - oder garnichts.)
      (Will man das AFW belassen, muss man - weniger intuitiv - den Dialog ins Form_Load des MainForms verlegen - und da hat man nur die Optionen: starten / canceln - nicht aber, das MainForm überhaupt erst zu bestimmen. Egal - gezeigt ists hier: Dialoge implementieren)

      Splash-Screen, mit wechselnden Nachrichten
      Splash-Screen wird bischen komplizierter, dafür ist das mit den Nachrichten sogar bischen einfacher als wie unter AFW. Nachrichten sind wichtig, denn ein Splash, der länger als 5 Sekunden lädt, sollte berichten, was grade gemacht wird.

      VB.NET-Quellcode

      1. Public Module Program
      2. <STAThread> _
      3. Public Sub Main()
      4. Dim frmSplash As frmSplash = Nothing
      5. Dim blocker As New ManualResetEventSlim
      6. Application.EnableVisualStyles()
      7. Application.SetCompatibleTextRenderingDefault(False)
      8. Dim frm As Form = Nothing
      9. Dim selected = MessageBox.Show("Möchten Sie (nach dem Splash) frmYes, frmNo - oder wollen Sie gleich canceln?", "Anmeldung", MessageBoxButtons.YesNoCancel)
      10. If selected = DialogResult.Cancel Then Return
      11. Dim th As New Thread(
      12. Sub()
      13. frmSplash = New frmSplash
      14. AddHandler frmSplash.Shown, Sub(s, e) blocker.Set() 'Mainthread freigeben
      15. frmSplash.ShowDialog()
      16. frmSplash.Dispose()
      17. blocker.Dispose()
      18. End Sub)
      19. th.Priority = ThreadPriority.Highest
      20. th.Start()
      21. blocker.Wait() ' hier Füsse still halten, bis der Splash angezeigt ist
      22. Dim message As Action(Of String) = Sub(s) frmSplash.Label1.Text = s
      23. frmSplash.BeginInvoke(message, String.Concat("Lade Daten für frm", selected))
      24. Thread.Sleep(1000)
      25. frmSplash.BeginInvoke(message, "lade immer noch (tue wenigstens so)")
      26. Thread.Sleep(1000)
      27. frmSplash.BeginInvoke(message, "gleich gehts los - ehrlich!")
      28. Thread.Sleep(1000)
      29. Select Case selected
      30. Case DialogResult.Yes : frm = New frmYes
      31. Case DialogResult.No : frm = New frmNo
      32. Case Else : Throw New ArgumentException("unknown User-Selection")
      33. End Select
      34. frmSplash.BeginInvoke(DirectCast(AddressOf frmSplash.Close, Action))
      35. Application.Run(frm)
      36. My.Settings.Save()
      37. End Sub
      38. End Module
      Bei Cancel wird natürlich sofort beendet (#11), ansonsten wird das Ergebnis des "AnmeldeDialogs" erstmal in der selected-Variablen gemerkt (#10).
      Dann wird ein Thread erstellt mit einer anonymen Methode, die den Splash erzeugt, in dessen Shown-Event das ManualResetEvent signalisiert wird (zeile#15) - damit der MainThread fortfahren kann. Danach den Splash mit .ShowDialog anzeigen, und danach den Kram disposen (#16-#18).
      Dieses alles wird mit höchster Thread-Priorität gestartet, und dann geht der MainThread selbst erstmal ins Koma (#20-22), mittels ManualResetEvent, aus dem er erst erwacht, wenn der NebenThread den Splash angezeigt hat (zur Erinnerung: zeile#15).
      Bei Erwachen die Daten laden (und Meldungen darüber abschicken) (#24 - 29) - so viele es auch sein mögen, und dann erst wird die Selection ausgewertet, welches Form anzuzueigen ist (#32 o. 33) - dann noch den Splash im NebenThread schließen (#35), und dann glücklich das MainForm starten, mit:

      VB.NET-Quellcode

      1. Application.Run(frm)
      Uff!

      (Hier zum Vergleich noch die AFW-Alternative: Splash-Screen mit Status-Meldungen)

      (Einen habich noch): general ExceptionHandling mit bedingter Kompilierung
      Wir können jetzt auch sehr schön dafür sorgen, dass in der Release-Version beim Absturz nur noch unsere eigenen Meldungen kommen, und keine Meldungen der Runtime, die dem User ja ebenso unverständlich sind, wie dem Entwickler wertvoll (mehr noch: Angreifer provozieren oft Fehler, um aus unkontrollierten Fehlermeldungen auf Schwachstellen zu schließen (dann muss aber das Logging aber erst recht geschützt werden)).
      Ausserdem ists für Support-Zwecke wichtig, dass Abstürze von Releases geloggt werden. Mit bedingter Kompilierung kann man diese Fehlerbehandlung zur Entwicklungszeit abstellen, denn da wollen wir ja kein Logging, sondern Fehler sollen durch den VisualStudio-Debugger debugt werden.
      Also die whole Story des Program-Moduls der angehängten Anwendung sieht so aus:

      VB.NET-Quellcode

      1. Imports System.Threading
      2. Public Module Program
      3. <STAThread> _
      4. Public Sub Main()
      5. Dim frmSplash As frmSplash = Nothing
      6. Dim blocker As New ManualResetEventSlim
      7. Application.EnableVisualStyles()
      8. Application.SetCompatibleTextRenderingDefault(False)
      9. #If CONFIG = "Release" Then
      10. AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf AppDomain_Exception
      11. #End If
      12. Dim frm As Form = Nothing
      13. Dim selected = MessageBox.Show("Möchten Sie (nach dem Splash) frmYes, frmNo oder wollen Sie gleich Canceln?", "Anmeldung", MessageBoxButtons.YesNoCancel)
      14. If selected = DialogResult.Cancel Then Return
      15. Dim th As New Thread(
      16. Sub()
      17. frmSplash = New frmSplash
      18. AddHandler frmSplash.Shown, Sub(s, e) blocker.Set() 'Mainthread freigeben
      19. frmSplash.ShowDialog()
      20. frmSplash.Dispose()
      21. blocker.Dispose()
      22. End Sub)
      23. th.Priority = ThreadPriority.Highest
      24. th.Start()
      25. blocker.Wait() ' solange der Splashscreen in seim Thread mit höchster Priorität gestartet wird, hier die Füsse still halten
      26. Dim message As Action(Of String) = Sub(s) frmSplash.Label1.Text = s
      27. frmSplash.BeginInvoke(message, String.Concat("Lade Daten für frm", selected))
      28. Thread.Sleep(1000)
      29. frmSplash.BeginInvoke(message, "lade immer noch (tue wenigstens so)")
      30. Thread.Sleep(1000)
      31. frmSplash.BeginInvoke(message, "gleich gehts los - ehrlich!")
      32. Thread.Sleep(1000)
      33. Select Case selected
      34. Case DialogResult.Yes : frm = New frmYes
      35. Case DialogResult.No : frm = New frmNo
      36. Case Else : Throw New ArgumentException("unknown User-Selection")
      37. End Select
      38. frmSplash.BeginInvoke(DirectCast(AddressOf frmSplash.Close, Action))
      39. Application.Run(frm)
      40. My.Settings.Save()
      41. End Sub
      42. Private Sub AppDomain_Exception(sender As Object, e As UnhandledExceptionEventArgs)
      43. MessageBox.Show("Hier wäre die Exception zu loggen, und dem User eine Mitteilung zu machen, ohne Implementations-Details zu verraten", "Fehler aufgetreten")
      44. End
      45. End Sub
      46. End Module
      (Ich habe auch in frmYes einen Fehler eingebaut, dass man sich überzeugen kann, dass er in Debug-Version debugt wird (im Startup!!), als Release aber abgefangen.)
      Dateien

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

      Entschuldige, dass ich auf diesen uralten Beitrag antworte.
      Ich schalte das Anwendungsframework ebenfalls immer ab und starte in ..main.
      EnableVisualStyles() ist mir klar, mach ich auch.

      Aber was macht

      VB.NET-Quellcode

      1. SetCompatibleTextRenderingDefault(False)
      ?


      Und ist

      VB.NET-Quellcode

      1. Application.Run(New Form1)


      das selbe wie

      VB.NET-Quellcode

      1. Form1.ShowDialog
      ?
      Liebe Grüße
      Roland Berghöfer

      Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
      Zu Frage Nummer 1 bin ich mal so frech und verlinke den MSDN-Beitrag dazu, Stichwort »schöner malen leicht gemacht.«

      dive26 schrieb:

      Und ist Application.Run(New Form1) das selbe wie Form1.ShowDialog?
      Nein. Das berüchtigte Form1.Show ist nur deshalb möglich, weil mehr im Hintergrund geschieht, als man glaubt. Da werden Form1-Instanzen heimlich erstellt und später kann man so drauf zugreifen, siehe Warum »Form1.Show« und Co. einem irgendwann ins Bein schießen
      Da es aber in der hier geschilderten Situation noch kein Form1-Objektinstanz gibt, geht das (wohl) nicht, siehe auch Dialoge richtig instanziieren
      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“ ()