2015-07-25 12 views
5

Ho una vecchia applicazione in Windows Form, che in molti posti esegue ricerche sul database. A volte ci vuole un sacco di tempo, quindi ho deciso di creare una schermata di caricamento in wpf per mostrare all'utente che qualcosa sta caricando in thread separati. Fondamentalmente è solo una finestra completamente trasparente con indicatore di caricamento (un cerchio di svolta). Tutto funziona perfettamente su Il mio computer host e sulla mia macchina virtuale, ma quando sto provando a distribuirlo nei nostri ambienti demo è come - inizia a caricare l'indicatore è mostrato e dopo pochi secondi scompare e l'applicazione smette di rispondere come per sempre. Il mio primo pensiero è che è il problema con l'accelerazione GPU, che non può elaborare la trasparenza, ma viene mostrato per pochi secondi, quindi non può essere il problema. Quindi molto probabilmente ho fatto qualcosa di male. Sotto Puoi vedere il mio codice, noti qualcosa che potrebbe essere sbagliato/causare un deadlock o qualcosa del genere?Problemi con lo schermo di caricamento in thread separati

public class LoadingManager 
    { 
    public LoadingManager() 
    { } 
    public LoadingManager(string LoadingText) 
    { 
     loadingText = LoadingText; 
    } 

    private string loadingText = "Please wait .."; 
    private Thread thread; 
    private bool ThreadReadyToAbort = false; 
    private BusyIndicatorView loadingWindow; 

    public void BeginLoading() 
    { 
     this.thread = new Thread(this.RunThread); 
     this.thread.IsBackground = true; 
     this.thread.SetApartmentState(ApartmentState.STA); 
     this.thread.Start(); 
    } 

    public void EndLoading() 
    { 
     if (this.loadingWindow != null) 
     { 
      this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => 
      { this.loadingWindow.Close(); })); 
      while (!this.ThreadReadyToAbort) { }; // I also tried to remove this while but it didn't help 
     } 
     this.thread.Abort(); 
    } 

    public void RunThread() 
    { 
     this.loadingWindow = new BusyIndicatorView(); 

     loadingWindow.tbLoadingCaption.Text = loadingText; 
     this.loadingWindow.Closing += new System.ComponentModel.CancelEventHandler(waitingWindow_Closed); 
     this.loadingWindow.ShowDialog(); 
    } 

    void waitingWindow_Closed(object sender, System.ComponentModel.CancelEventArgs e) 
    { 
     Dispatcher.CurrentDispatcher.InvokeShutdown(); 
     this.ThreadReadyToAbort = true; 
    } 

MODIFICA.

Ho notato che su questa macchina di solito (a volte fallisce anche al primo clic) funziona quando faccio clic su Cerca per la prima volta. Se faccio clic un'altra volta, viene visualizzato per un secondo che scompare e l'applicazione smette di rispondere. Quindi sembra che Thread non stia chiudendo, l'arresto del Dispatcher fallito? Ma nessuna eccezione viene lanciata ...

+0

perché stai usando un thread per mostrare una finestra? Il caricamento effettivo avviene sul thread principale? –

+0

Sì, il caricamento è nel thread principale, so che dovrebbe essere invertito, ma è la vecchia applicazione Windows Form. Ci vorrebbe un grande sforzo per riscriverlo. – MajkeloDev

+0

WinForms o WPF? Meglio essere chiari su questo –

risposta

2

Il metodo BeginLoading può essere richiamato più volte prima che sia terminato, e quindi può creare più di una finestra wpf. Questo rovina tutti i tipi di riferimenti. Inoltre, non interrompere il thread, lasciare che decida da solo. Qui ci sono le due modifiche:

public void BeginLoading() 
{ 
    this.thread = new Thread(this.RunThread); 
    this.thread.IsBackground = true; 
    this.thread.SetApartmentState(ApartmentState.STA); 
    this.thread.Start(); 
    while (this.loadingWindow == null) { } // <--- Add this line 
} 

public void EndLoading() 
{ 
    if (this.loadingWindow != null) 
    { 
     this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => 
     { this.loadingWindow.Close(); })); 
     while (!this.ThreadReadyToAbort) { }; 
    } 
    //this.thread.Abort(); // <-- Remove this line 
} 

Anche se tutto questo è solo per uno schermo occupato, direi che ci deve essere un modo migliore e più sicuro di questo. Per scopi accademici questo è un problema interessante, ma non il codice di produzione, soprattutto se qualche sviluppatore junior potrebbe giocherellare con questo in futuro.

Modifica: Arresto anomalo sulla mia macchina anche se riduco il ritardo tra le chiamate ripetute a BeginLoading e EndLoading. Potrebbe essere correlato a come la finestra wpf si chiude in modo asincrono. Ho rimosso il gestore di eventi chiusa e appena usato un flag booleano per indicato che la finestra 'IsLoaded' o no, e non ho visto alcun problema con questo:

public class LoadingManager2 
{ 
    public LoadingManager2() 
    { } 
    public LoadingManager2(string LoadingText) 
    { 
    loadingText = LoadingText; 
    } 

    private string loadingText = "Please wait .."; 
    private Thread thread; 
    private MyWindow loadingWindow; 
    private bool isLoaded = false; 

    public void BeginLoading() 
    { 
    this.thread = new Thread(this.RunThread); 
    this.thread.IsBackground = true; 
    this.thread.SetApartmentState(ApartmentState.STA); 
    this.thread.Start(); 
    while (!this.isLoaded) { }; 
    } 

    public void RunThread() 
    { 
    this.loadingWindow = new MyWindow(); 
    this.isLoaded = true; 
    this.loadingWindow.ShowDialog(); 
    } 

    public void EndLoading() 
    { 
    this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => 
    { 
     this.loadingWindow.Close(); 
     this.isLoaded = false; 
    })); 
    while (this.isLoaded) { }; 
    } 
} 
+0

Interessante. Farò un tentativo in poche ore e ti faccio sapere come è andata. – MajkeloDev

Problemi correlati