Feedback

C# - WPF-Splash-Fenster

Veröffentlicht von am 8/24/2010
(1 Bewertungen)
Splash-Fenster sind Fenster, die beim Starten einer Anwendung erscheinen, um dem Anwender
während einer länger andauernden Initialisierungsphase Informationen anzubieten oder um einfach nur anzuzeigen, dass das Programm im Moment initialisiert wird.

Ein vernünftiges Splash-Fenster ist unter WPF aber erstaunlicherweise gar nicht so einfach zu
implementieren. Ein im Startup-Ereignis der App-Instanz direkt angezeigtes Splash-Fenster kann zum Beispiel keine Informationen anzeigen, die während der Initialisierung ausgegeben werden sollen. Außerdem werden Animationen, die auf dem Splash-Fenster angelegt sind, nicht ausgeführt.

Eine Lösung dieser Probleme ist, die Initialisierung der Anwendung im Startup-Ereignis der App-Instanz asynchron auszuführen und das Splash-Fenster ebenfalls asynchron zu schließen.

Die folgende Lösung entstammt dem Buch "Das C# 2010 Codebook" und wurde vom Autor mit freundlicher Genehmigung des Verlags veröffentlicht.
/* Dieses Snippet ist eines der 418 Rezepte des Buchs "Das C# 2010 Codebook" und wurde vom Autor mit freundlicher Genehmigung des Verlags veröffentlicht. */

/* Basis dieser Lösung ist, dass Sie in der App.xaml-Datei kein Startfenster angeben. 
Das Startfenster wird, neben dem Splash-Fenster, von einem asynchron aufgerufenen 
Delegaten in der überschriebenen OnStartup-Methode der Anwendung geöffnet. */

/* Der XAML-Code des Beispiel-Splash-Fensters */

<Window x:Class="..."
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="180" Width="280"
    WindowStyle="None">
   <Grid>
      <TextBlock Name="txtInfo" Margin="10,10,0,28" TextWrapping="Wrap" 
         HorizontalAlignment="Left" Width="166">Info</TextBlock>
      <ProgressBar Name="pbr" Height="20" VerticalAlignment="Bottom"/>
   </Grid>
</Window>

/* Methode in der Klasse des Splash-Fensters */
public void SetInfo(string info, int progress)
{
   this.txtInfo.Text = info;
   this.pbr.Value = progress;
}

/* Die App-Klasse */
public partial class App : Application
{
   protected override void OnStartup(StartupEventArgs e)
   {
      base.OnStartup(e);

      // Splash-Fenster öffnen
      SplashWindow splashWindow = new SplashWindow();
      splashWindow.Show();

      // Delegat für die asynchrone Ausführung
      // der Initialisierung
      Action initializer = new Action(() =>
      {
         // Simulation einer Initialisierung
         try
         {
            /*  Initialisierung */
            for (int i = 0; i < 100; i++)
            {
               // Das Splash-Fenster aktualisieren
               splashWindow.Dispatcher.Invoke(DispatcherPriority.Normal,
                   new Action(() =>
                   {
                      splashWindow.SetInfo("Lese Datensatz " + i + " ...", i);
                   }));

               // Die eigentliche Initialisierung wird hier nur simuliert
               System.Threading.Thread.Sleep(30);
            }
            /* Ende der Initialisierung */
         }
         catch (Exception ex)
         {
            MessageBox.Show("Fehler beim Initialisieren: " + ex.Message,
               "Splash-Fenster", MessageBoxButton.OK, MessageBoxImage.Error);
            this.Shutdown();
         }
      });

      // Delegat für den Callback der asynchronen Ausführung
      AsyncCallback splashCloser = new AsyncCallback((result) =>
      {
         // Das Hauptfenster erzeugen, der Anwendung zuweisen
         // und öffnen
         this.Dispatcher.Invoke(DispatcherPriority.Normal,
            new Action(() =>
            {
               MainWindow mainWindow = new MainWindow();
               this.MainWindow = mainWindow;
               mainWindow.Show();
            }));

         // Schließen des Splash-Fensters
         splashWindow.Dispatcher.Invoke(DispatcherPriority.Normal,
            new Action(() =>
            {
               splashWindow.Close();
            }));
      });

      // Asynchrones Starten der Initialisierung
      initializer.BeginInvoke(splashCloser, null);
   }
}
Abgelegt unter WPF, Splash.

1 Kommentare zum Snippet

Günther Foidl schrieb am 9/3/2010:
Für einfache 'SplashScreens' genügt es bei einm Bild im Projekt die 'BuildAction = SplashScreen' zu setzen. Es wird dann halt dieses statische Bild angezeigt, aber wenigsten wird Fade-In/Out automatisch erledigt.
 

Logge dich ein, um hier zu kommentieren!