2013-03-08 9 views
6

otrzymują klasę niżej, aby uruchomić ekran powitalny na alternatywnym wątku:TPL Odpowiednik klasy Thread „Splash-type” ekran

public partial class SplashForm : Form 
{ 
    private static Thread _splashThread; 
    private static SplashForm _splashForm;  

    public SplashForm() 
    { 
     InitializeComponent(); 
    } 

    // Show the Splash Screen (Loading...)  
    public static void ShowSplash()  
    {   
     if (_splashThread == null)   
     {    
      // Show the form in a new thread.   
      _splashThread = new Thread(new ThreadStart(DoShowSplash));    
      _splashThread.IsBackground = true;    
      _splashThread.Start();   
     }  
    }  

    // Called by the thread. 
    private static void DoShowSplash()  
    {   
     if (_splashForm == null)    
      _splashForm = new SplashForm();  

     // Create a new message pump on this thread (started from ShowSplash).  
     Application.Run(_splashForm); 
    }  

    // Close the splash (Loading...) screen. 
    public static void CloseSplash()  
    {   
     // Need to call on the thread that launched this splash.  
     if (_splashForm.InvokeRequired)    
      _splashForm.Invoke(new MethodInvoker(CloseSplash));   
     else    
      Application.ExitThread();  
    } 
} 

To się nazywa i zamknięte z następujących odpowiednich poleceń

SplashForm.ShowSplash(); 
SplashForm.CloseSplash(); 

Dobrze.

nie jestem dokładnie nowy w OC, oczywiście możemy pokazać postać w innym wątku, używając coś tak prostego jak:

Task task = Task.Factory.StartNew(() => 
{ 
    SomeForm someForm = new SomeForm(); 
    someForm.ShowDialog(); 
}; 

Mój problem jest zamknięcie tej SomeForm dół, gdy jesteś gotowy. Musi być lepszy sposób niż tworzenie metodę public static w klasie SomeForm jak

private static SomeForm _someForm; 
public static void CloseSomeForm()  
{   
    if (_someForm.InvokeRequired)    
     _someForm.Invoke(new MethodInvoker(CloseSomeForm));   
} 

moje pytanie, co jest najlepszym sposobem, aby zrobić to samo, co pokazano za pomocą klasy SplashForm powyżej za pomocą zadania Parrallel Library (TPL)? W szczególności najlepszy sposób zamknięcia formularza wywoływanego w innym wątku z interfejsu użytkownika.

+0

Jaki jest celem jest umieszczenie ekranu powitalnego na innym wątku? –

+1

Aby było aktywne (wyświetlaj animacje itp.). Nie blokuj interfejsu użytkownika. – MoonKnight

Odpowiedz

2

Twoje pytanie nie wydaje się tak bardzo o różnicę między Thread i Task, ponieważ to, czego chcesz, to pozbyć się "brudnego" stanu statycznego. Proponuję zamknąć go w klasie:

class SplashController 
{ 
    public void Run() { 
     _someForm = new SomeForm(); 
     someForm.ShowDialog(); 
    } 

    private SomeForm _someForm; 
    public void CloseSomeForm()  
    {   
     if (_someForm.InvokeRequired)    
      _someForm.Invoke(new MethodInvoker(CloseSomeForm));   
    } 
} 

Możesz zadzwonić Uruchom używając dowolnego mechanizmu wątków. CloseSomeForm nie używa wątków, więc jest niezależny od tego problemu.

Możesz teraz przechowywać odwołanie do instancji SplashController, gdziekolwiek chcesz. W zmiennych lokalnych lub w zmiennej statycznej. Ta ostatnia ma sens, ponieważ istnieje dokładnie jeden ekran powitalny.

Ponieważ stan statyczny jest teraz dobrze hermetyzowany, nie widzę problemu z jego statycznym utrzymaniem.

+0

Świetna odpowiedź, świetny pomysł, w ogóle o tym nie myślisz !? Mój główny uchwyt do tego, co wcześniej miałem, to użycie 'InvokeRequired'. Przypuszczam, że nie ma innego ładniejszego mechanizmu robienia tego, co chcę. – MoonKnight

+1

TPL ma sposób na wywołanie połączenia do wątku interfejsu użytkownika przy użyciu TaskScheduler.FromCurrentSynchronizationContext. Niestety, ta metoda musi zostać wywołana w wątku interfejsu użytkownika w celu uzyskania programu planującego. Aby go użyć, musisz zagrać w tańcu, aby uzyskać go w wątku UI i przenieść go do innego wątku. Nie polecałbym tego. – usr

+0

Jestem świadomy trasy "TaskScheduler", ale w tym przypadku nie jest to dobre z powodów, które zadeklarowałeś. W powyższym myślę, że chciałeś 'Run() {_ someForm = new SomeForm(); ...}'. – MoonKnight

2

Prawdopodobnie nie powinien zrobić coś takiego

Task task = Task.Factory.StartNew(() => 
{ 
    SomeForm someForm = new SomeForm(); 
    someForm.ShowDialog(); 
}; 

ponieważ wymagałoby to pętlę wiadomość będzie obecna na dokładnym wątku, który tworzy formę, która jest gwint pula wątków. Ale tego nie przetestowałem.

Można spróbować to:

public static Task<SplashForm> ShowSplash()  
{   
    var tcs = new TaskCompletionSource<SplashForm>(); 

    // Show the form in a new thread.   
    _splashThread = new Thread(() => 
    { 
     var splashForm = new SplashForm();  

     tcs.SetResult(_splashForm); 

     // Create a new message pump on this thread (started from ShowSplash).  
     Application.Run(splashForm); 
    }); 

    _splashThread.IsBackground = true;    
    _splashThread.Start();   
}  

pozwoliłoby na usunięcie statyczny modyfikator z CloseSplash:

// Close the splash (Loading...) screen. 
public void CloseSplash()  
{   
    // Need to call on the thread that launched this splash.  
    if (this.InvokeRequired)    
     this.Invoke(new MethodInvoker(CloseSplash));   
    else    
     Application.ExitThread();  
} 

mogą być używane tak:

var form = await SplashForm.ShowSplash(); 
form.CloseSplash(); 
+0

Podoba mi się to. Dziękuję za Twój czas. – MoonKnight

+0

Należy pamiętać, że funkcja SetResult może być wykonywana synchronicznie i może pojawić się dziwne zachowanie, w zależności od tego, co zrobi się po oczekiwaniu, że może nie trafić w wierszu Application.Run, gdy wydaje się, że należy. W razie wątpliwości należy załadować SetResult w oddzielnym zadaniu (z Task.Run). –

+0

@bluesman Masz moją uwagę z komentarzem. Chcesz wyjaśnić trochę więcej? – Joel