2012-11-03 8 views
9

C# WPF ApplicationSplashScreen.Close (Timespan.FromMilliseconds (int)): Czy zostało wysłane zdarzenie w Timespan Complete?

mam SplashScreen są wyświetlane przy uruchamianiu na minimalnym czasie za pomocą

Thread.Sleep(int); //int = milliseconds to display splash screen 

Kiedy ten czas snu zostanie osiągnięta, kod zostanie wznowiony i ekran powitalny zanika do zamknięcia przez stosując

SplashScreen.Close(Timespan.FromMilliseconds(int)); //int = milliseconds fade-out 

Chciałbym, aby wstrzymać w tym momencie poczekać, aż ekran powitalny stała się 100% przezroczyste i jest całkowicie zamknięty, a następnie kontynuować z innymi zadaniami, IE Pisanie do konsoli lub wyświetlanie MainWindow.

Czy zostało wywołane zdarzenie po zakończeniu (TimeSpan.FromMilliseconds (int))? Jakieś inne sugestie?

namespace StartupSplash 
{ 
    public class SplashScreenStartup 
    { 
     //IMPORTANT:set image property to Resource and NOT Splash Screen 
     private SplashScreen Splash = new SplashScreen("Resources/SplashScreen.png"); 

     public void SplashScreenStartUp() 
     { 
      Splash.Show(false, true); 
      Thread.Sleep(3000); // Pause code, display splash screen 3 seconds 
      Splash.Close(TimeSpan.FromMilliseconds(3000)); // 3 second splash fade-out 
      // I want to wait until splash screen fadeOut has completed before 
      // this next console output is performed. 
      Console.WriteLine("Executes before Splash fadeOut completes."); 
     } 

    } 
+1

Zakładam, że to jest WPF? –

+0

Tak, jest.Dziękuję za wskazanie tego. – reido113

+2

Dlaczego nie zrobisz tego w wątku i po prostu poczekasz, aż wątek się zakończy, powinien otrzymać wyniki, które chcesz, i po prostu zaimplementować. –

Odpowiedz

0

Nigdy nie znalazłem wydarzenia, którego należałoby posłuchać po ukończeniu TimeSpan. Ponadto, po podjęciu decyzji o zatrzymaniu wątków, zdecydowałem się zamiast tego użyć DispatcherTimers.

(Mam rozcieńczona i zawierał logikę w tej jednej klasy do celów referencyjnych)

using System; 
using System.Windows; 
using System.Windows.Threading; 


namespace StartupSplash2 
{ 

public partial class MainWindow : Window 
{ 
    private DispatcherTimer visibleTimer; 
    private DispatcherTimer fadeoutTimer; 
    private SplashScreen splash; 
    private int visibleTime = (4000); //milliseconds of splash visible time 
    private int fadeoutTime = (1500); //milliseconds of splash fadeout time 

    public MainWindow() 
    { 
     //hide this MainWindow window until splash completes 
     this.Visibility = Visibility.Hidden; 
     InitializeComponent(); 
     splashIn(); //start the splash 
    } 

    private void splashIn() 
    { 
     splash = new SplashScreen("Resources/SplashScreen.png"); //ensure image property is set to Resource and not screen saver 
     visibleTimer = new DispatcherTimer(); //timer controlling how long splash is visible 
     visibleTimer.Interval = TimeSpan.FromMilliseconds(visibleTime); 
     visibleTimer.Tick += showTimer_Tick; //when timer time is reached, call 'showTimer_Tick" to begin fadeout 
     splash.Show(false, true); //display splash 
     visibleTimer.Start(); 
    } 

    private void showTimer_Tick(object sender, EventArgs e) 
    { 
     visibleTimer.Stop(); 
     visibleTimer = null; //clear the unused timer 
     fadeoutTimer = new DispatcherTimer(); 
     fadeoutTimer.Interval = TimeSpan.FromMilliseconds(fadeoutTime); //a timer that runs while splash fades out and controlls when main window is displayed 
     fadeoutTimer.Tick += fadeTimer_Tick; //when fadeout timer is reached, call 'fadeTimer_Tick' to show main window 
     splash.Close(TimeSpan.FromMilliseconds(fadeoutTime)); //begin splash fadeout to close 
     fadeoutTimer.Start(); 
    } 

    private void fadeTimer_Tick(object sender, EventArgs e) 
    { 
     fadeoutTimer.Stop(); 
     fadeoutTimer = null; //clear the unused timer 
     splash = null; //clear the splash var 
     MainWindowReady(); //call method to display main window 
    } 

    public void MainWindowReady() 
    { 
     this.Visibility = Visibility.Visible; 
     //Here is the start of the Main Window Code 
     this.Content = "Ok, the app is ready to roll"; 
    } 

    } 
} 
3

Może ten kod może ci pomóc. Korzystanie z klasy BackgroundWorker:

BackgroundWorker worker = new BackgroundWorker(); 
worker.DoWork += (o, ea) => 
{ 
    // Dispatcher.Invoke commands the dispatcher to do something 
    Dispatcher.Invoke((Action)(() => Splash.Close(TimeSpan.FromMilliseconds(3000))); 
    // Sleeps this worker but NOT the UI 
    Thread.Sleep(3000); 
}; 
worker.RunWorkerCompleted += (o, ea) => 
{ 
    // Open your mainwindow sample 
    MainWindow w = new MainWindow(); 
    w.Show(); 
}; 

//Runs the worker on its own thread 
worker.RunWorkerAsync(); 

ten powinien rozpocząć zamykanie swojej ekran powitalny, a następnie przez nią spać, a gdy to się robi to będzie otworzyć MainWindow. W rzeczywistości używam czegoś bardzo podobnego do tego, aby zaimplementować dane logowania i pobierania dla mojej aplikacji WPF, wyświetlając pasek postępu i aktualizując tekst w taki sposób, aby wyświetlał się na przykład "Łączenie z serwerem", "Logowanie" i "Pobieranie danych".

+0

Dziękuję za ten kierunek. Na początku miałem kilka błędów, ponieważ nawiasy klamrowe, które kończą się .DoWork i .RunWorkerCompleted po nich wymagały średników. Ale wciąż dostaję błędy związane z Dispatcherem. Invoke. Podczas próby rozwiązania tego znalazłem następujący kod do pracy. – reido113

+0

O kurwa, przepraszam! Twój błąd: dyspozytor nie trafia wspornika na końcu. O pracowniku tła: Zauważyłem, że możesz po prostu umieścić w nim swój kod i zobaczyć, jak idzie. Jeśli robienie czegoś daje wyjątek lub coś podobnego, użyj akcji dispatcher.invoke. Jeśli otrzymujesz coś (np. Int fadeOutTime) i pojawia się błąd, sprawdź, czy możesz zamiast tego użyć statycznego elementu. To bardzo proste i bardzo podoba mi się ta klasa. Bez dziwnych rzeczy z wątkami startowymi i blokującymi, powinno to być zrobione tylko wtedy, gdy chcesz osiągnąć optymalną wydajność, jak w Battlefield 3 lub coś podobnego. Nie po to, żeby pokazać SS. – AmazingDreams

1

Znalazłem następujący kod działa. Nie jestem do końca jasne, dlaczego i będę zagłębić się bliżej, aby lepiej to zrozumieć.

Proszę krytykować w razie potrzeby, jestem tutaj, aby się uczyć i dzielić. Twoje zdrowie.

class Tester 
    { 
    // Create splash screen instance and reference the image location. 
    // IMPORTANT Ensure that the image properties are set to Resource and NOT Splash Screen 
    private SplashScreen Splash = new SplashScreen("Resources/SplashScreen.png"); 

    public void Display() 
    { 
     Splash.Show(false, true); 
     // pause the code, thus, displaying the splash for 3 seconds 
     Thread.Sleep(3000); 
     // close the splash 
     Close(); 
    } 

    private void Close() 
    { 
     // sets the fadeout time in milliseconds 
     int fadeOutTime = 1500; 

     // wait until the splash screen fadeOut has completed before writing to the console 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += (o, ea) => 
     { 
      // Run background task (fade out and close the splash) 
      Splash.Close(TimeSpan.FromMilliseconds(fadeOutTime)); 
      // Sleep this worker but NOT the UI (for the same time as the fade out time) 
      Thread.Sleep(fadeOutTime); 
     }; 
     worker.RunWorkerCompleted += (o, ea) => 
     { 
      // Execute task after splash has closed completely 
      Console.WriteLine("This is after the splash screen fadeOut completes."); 
     }; 
     // start the background task, on it's own thread 
     worker.RunWorkerAsync(); 
    } 

} 
+2

Ummm ... Wyświetlam tylko ekran powitalny, gdy inicjalizacja mojej aplikacji trwa tak długo, że użytkownik mógł w inny sposób założyć, że nie kliknął poprawnie skrótu, i dlatego kliknął ponownie, uruchamiając jednocześnie dwie instancje aplikacji (co oba starają się uruchomić dwa razy więcej czasu) ... więc ... NAPRAWDĘ zaleciłbym sposób, aby NIE zasypiać głównego wątku, gdy wyświetlany jest ekran powitalny, aby mógł zainicjować twoją aplikację. i jeśli główna forma ładuje się i wyświetla BEHIND na ekranie powitalnym (wskazówka: zawsze na wierzchu), to jakie są uszkodzenia? Twoje zdrowie. Keith. – corlettk

+0

Bardzo dobre punkty Keith. Dziękuję za te sugestie. Poprawię to, gdy lepiej poznam BackgroundWorker i wielowątkowość. Zdrowie przyjacielu. Reid – reido113

+0

Moją podstawową ideą jest przesunięcie WSZYSTKIEGO do zrobienia z SplashScreen w metodzie DoWork ... tak, aby było pokazane, wstrzymane i wyciszone w wątku tła ... to jest tylko jedno wywołanie metody w głównym zdarzeniu FormLoaded Handler do ShowSplashScreenInTheBackground ... ale utknąłem, aby to pokazać w ten sposób ... westchnienie! – corlettk

0

W końcu doszedłem do wniosku, że szczerzę złe drzewo w poprzednich komentarzach. Wyświetlanie SplashScreen w tle jest zarówno problematyczne (odmówiło zamknięcia automatycznie, bez względu na to, co próbowałem) i unnessary. Oto, co otrzymałem ... Naprawdę proste!

using System; 
using System.Net; 
using System.Windows; 

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
    public Window1() { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) { 
     // show the splash screen 
     // nb: Resources/SplashScreenImage.png file Properties ~ Build Action='Resource' 
     var splashScreen = new SplashScreen("Resources/SplashScreenImage.png"); 
     splashScreen.Show(false); // don't close automatically 
     // ... initialise my application ... 
     Initialise(); 
     // close the splash screen. 
     splashScreen.Close(TimeSpan.FromMilliseconds(250D)); 
    } 

    private void Initialise() { 
     // do my long-running application initialisation on the main thread. 
     // In reality you'd do this download asyncronously, but in this case 
     // it serves as a simple proxy for some "heavy" inititalisation work. 
     textBox1.Text = new WebClient().DownloadString("http://stackoverflow.com/questions/13213625/splashscreen-closetimespan-frommilliseconds-listen-for-closed-event"); 
    } 
    } 

} 

Mam nadzieję, że pomaga ... choć nie jestem wcale przekonany, że będzie ;-)

Cheers. Keith.

PS: Zastanawiam się, dlaczego plusk nie chciał się zamknąć? Domyślam się, że wewnętrznie polega na zdarzeniach, które są dostępne tylko (tj. Subskrybowalne) na odpowiedniku WPF w wątku ekspedycji zdarzeń (jakkolwiek by się nie nazywało).

+0

Na początku myślałem, że zdarzenie zostanie wywołane po zakończeniu TimeSpan. Starając się powstrzymać od zaprzestania tworzenia wątków, zacząłem stosować zamiast tego zegary. Otrzymam kod rozwiązania, jak tylko wrócę na właściwe tory. Co mnie to nauczyło. :) – reido113

0

znalazłem zdarzenie o nazwie SplashScreen.Dismissed który pozwala uruchomić aplikację po wygaśnięciu ekran powitalny. Jednak minimalny wymagany system operacyjny to Windows 8 i nie mogłem go użyć. Więcej informacji można znaleźć tutaj MSDN

Powiązane problemy