An einen SplashScreen stellt man folgende Anforderungen:
Um das zu verwenden muß man von der üblichen Architektur bisserl abweichen - vor allem kann man nun nicht mehr im Application.Xaml den StartupUri angeben. Dies deshalb, weil man ja codeseitige Kontrolle braucht über beide Windows: SplashWindow und MainWindow, damit man im MainWindow.ContentRendered-Event Zugriff auf den Splash hat, um ihn zu schließen.
Erläuterung zum Code
Im OnStartup() wird logischerweise als erstes der Splash gestartet, dann folgt die aufwändige Initialisierung mit gelegentlichen Meldungen an den Splash, dann wird das MainWindow erzeugt.
In dessen ContentRendered-Event (Zeile#16) wird der SplashScreen dann geschlossen und aufgeräumt.
Der Splash wird übrigens durch 2 Variablen repräsentiert: durch Splash (das in Xaml erstellte Window) und durch SplashVM, das codierte ViewModel des Splashes.
Die Kommunikation läuft übers Viewmodel, und wie daran gebunden wird steht auf einem anneren Blatt (im Xaml, um genau zu sein ;)).
Heikelster Punkt ist vlt. Zeile#25: da wird über den Dispatcher des Splashes mittels anonymer Function sein DataContext abgerufen, damit das Splash-Viewmodel hier verfügbar ist für die Kommunikation.
Invoking über den Dispatcher ist von Microsoft bisserl misdesigned, sodass immer einen Cast erforderlich ist. (Ich vermute ja, die haben da intern eine "Behörde für umständliches Design" - ähnlich dem britischen Ministry of Silly Walks ;).)
Jedenfalls habich gleich paar Extensions geproggt, mit denen man auch einfacher dispatchen kann (aber hier auskommentiert).
Eine noch eigenartigere Eigenart ist, dass im Application.OnStartup() die Resourcen der Application-Klasse u.U. noch gar nicht initialisiert sind. Das ist problematisch, denn dann kann das MainWindow nicht angezeigt werden, falls es eine der Application-Resourcen benötigt.
Lösung: Auslagern der Application-Resourcen in ResourceDictionaries:
Keine Ahnung, warum das hilft, aber es hilft ?(. Ist auch garnet schlecht, denn einen SplashScreen brauchen eh nur umfangreichen Anwendungen, bei denen es sowieso geraten ist, die vmtl. mannigfaltigen Anwendungs-Resourcen sinnvoll in ResourceDictionaries zu strukturieren.
- er soll im Nebenthread laufen, damit der vollständig mit Startup beschäftigte MainThread ihn nicht blockiert.
- Es soll einen Kommunikations-Mechanismus geben, über den der MainThread Nachrichten über den Fortschritt des eigentlichen StartVorgangs der Anwendung senden und anzeigen kann.
VB.NET-Quellcode
- Imports System.Threading
- Class Application
- Private _Splash As Splash
- Private _SplashVM As SplashVM
- Protected Overrides Sub OnStartup(e As StartupEventArgs)
- MyBase.OnStartup(e)
- StartSplash()
- Thread.Sleep(1300) '"aufwändige Initialisierung"
- TrySplashMessage("erste Meldung vom LadeProzess")
- Thread.Sleep(1000)
- TrySplashMessage("oh, ich muß noch bisserl überlegen")
- Thread.Sleep(1000)
- Dim w = New MainWindow()
- AddHandler w.ContentRendered, Sub(s, cre) _Splash.Dispatcher.BeginInvoke(DirectCast(AddressOf CleanUpSplash, Action))
- 'AddHandler w.ContentRendered, Sub(s, cre) _Splash.DispatchInvoke(AddressOf CleanUpSplash)
- MainWindow = w
- w.Show()
- End Sub
- ''' <summary> splashMessage will be omitted, if the splash isn't ready yet </summary>
- Private Sub TrySplashMessage(splashMessage As String)
- If _Splash Is Nothing Then Return
- If _SplashVM Is Nothing Then
- _SplashVM = DirectCast(_Splash.Dispatcher.Invoke(DirectCast(Function() _Splash.DataContext, Func(Of Object))), SplashVM)
- '_SplashVM = DirectCast(_Splash.DispatchInvoke(Function() _Splash.DataContext), SplashVM)
- End If
- 'implement your own Progress-Reporting, e.g. with Progressbars, slide-shows or whatever
- _SplashVM.Text = splashMessage
- End Sub
- Private Sub StartSplash()
- Dim thr = New Thread(Sub()
- _Splash = New Splash()
- _Splash.ShowDialog()
- End Sub)
- thr.Priority = ThreadPriority.Highest
- thr.SetApartmentState(ApartmentState.STA)
- thr.Start()
- End Sub
- Private Sub CleanUpSplash()
- _Splash.Close()
- 'making objects inaccessible from code enables the GarbageCollector to clean them up
- _Splash = Nothing
- _SplashVM = Nothing
- End Sub
- End Class
Erläuterung zum Code
Im OnStartup() wird logischerweise als erstes der Splash gestartet, dann folgt die aufwändige Initialisierung mit gelegentlichen Meldungen an den Splash, dann wird das MainWindow erzeugt.
In dessen ContentRendered-Event (Zeile#16) wird der SplashScreen dann geschlossen und aufgeräumt.
Der Splash wird übrigens durch 2 Variablen repräsentiert: durch Splash (das in Xaml erstellte Window) und durch SplashVM, das codierte ViewModel des Splashes.
Die Kommunikation läuft übers Viewmodel, und wie daran gebunden wird steht auf einem anneren Blatt (im Xaml, um genau zu sein ;)).
Heikelster Punkt ist vlt. Zeile#25: da wird über den Dispatcher des Splashes mittels anonymer Function sein DataContext abgerufen, damit das Splash-Viewmodel hier verfügbar ist für die Kommunikation.
Invoking über den Dispatcher ist von Microsoft bisserl misdesigned, sodass immer einen Cast erforderlich ist. (Ich vermute ja, die haben da intern eine "Behörde für umständliches Design" - ähnlich dem britischen Ministry of Silly Walks ;).)
Jedenfalls habich gleich paar Extensions geproggt, mit denen man auch einfacher dispatchen kann (aber hier auskommentiert).
Eine noch eigenartigere Eigenart ist, dass im Application.OnStartup() die Resourcen der Application-Klasse u.U. noch gar nicht initialisiert sind. Das ist problematisch, denn dann kann das MainWindow nicht angezeigt werden, falls es eine der Application-Resourcen benötigt.
Lösung: Auslagern der Application-Resourcen in ResourceDictionaries:
XML-Quellcode
- <Application x:Class="Application"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
- <!-- hier kein StartupUri! -->
- <Application.Resources>
- <ResourceDictionary>
- <ResourceDictionary.MergedDictionaries>
- <ResourceDictionary Source="ResourceDicts/Other.xaml"/>
- </ResourceDictionary.MergedDictionaries>
- </ResourceDictionary>
- </Application.Resources>
- </Application>
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()