2009-12-16 9 views

Odpowiedz

46

Korzystanie z oddzielnego wątku, aby wyświetlić proste proszę czekać wiadomość jest przesadą, zwłaszcza jeśli nie masz dużego doświadczenia z gwintem.

O wiele prostszym rozwiązaniem jest utworzenie formularza "Proszę czekać" i wyświetlenie go jako okna bez trybu tuż przed wolniej załadowanym formularzem. Po zakończeniu ładowania głównego formularza ukryj formularz oczekiwania.

W ten sposób używasz tylko jednego głównego wątku interfejsu użytkownika, aby najpierw wyświetlić formularz oczekiwania, a następnie załadować główny formularz.

Jedynym ograniczeniem tego podejścia jest to, że formularz oczekiwania nie może być animowany (taki jak animowany GIF), ponieważ wątek jest zajęty ładowaniem głównego formularza.

+0

istnieć drogę do korzystania animowanych obrazów w swoim podejściu do jeszcze animowany? – Sadegh

+1

@Sadegh, należy użyć formantu na formularzu oczekiwania, które wewnętrznie tworzy wątek do animowania obrazu. Nie sądzę, aby standard PictureBox to zrobił. Jeśli jednak zdecydowanie potrzebujesz animacji, warto przyjrzeć się linkowanym stronom Davida. – Ash

+5

Nigdy nie używaj 'Application.DoEvents();'! –

15

Chcesz spojrzeć na ekrany "Splash".

Wyświetl inny formularz "Splash" i poczekaj, aż przetwarzanie zostanie wykonane.

Oto szybkie i brudne post, jak to zrobić.

Tutaj jest lepiej example.

4

Powinieneś utworzyć wątek tła, aby utworzyć i wypełnić formularz. Umożliwi to wątkowi pierwszego planu wyświetlenie komunikatu ładowania.

+4

Nie można naprawdę stworzyć i użyć formularza w Windows Forms w wątku non-UI .... –

5

Proste rozwiązanie:

using (Form2 f2 = new Form2()) 
{ 
    f2.Show(); 
    f2.Update(); 

    System.Threading.Thread.Sleep(2500); 
} 

A potem podstawić swój Ładowanie do uśpienia.

21

Przyjrzałem się większości opublikowanych rozwiązań, ale natrafiłem na inny, który preferuję. To proste, nie używa wątków i działa na to, co chcę.

http://weblogs.asp.net/kennykerr/archive/2004/11/26/where-is-form-s-loaded-event.aspx

I do roztworu dodaje się w artykule i przeniósł kod do klasy bazowej że wszystkie moje postacie dziedziczą z. Teraz po prostu wywołać jedną funkcję: ShowWaitForm() podczas zdarzenia frm_load() dowolnego formularza, który wymaga okna dialogowego oczekiwania podczas ładowania formularza. Oto kod:

public class MyFormBase : System.Windows.Forms.Form 
{ 
    private MyWaitForm _waitForm; 

    protected void ShowWaitForm(string message) 
    { 
     // don't display more than one wait form at a time 
     if (_waitForm != null && !_waitForm.IsDisposed) 
     { 
      return; 
     } 

     _waitForm = new MyWaitForm(); 
     _waitForm.SetMessage(message); // "Loading data. Please wait..." 
     _waitForm.TopMost = true; 
     _waitForm.StartPosition = FormStartPosition.CenterScreen; 
     _waitForm.Show(); 
     _waitForm.Refresh(); 

     // force the wait window to display for at least 700ms so it doesn't just flash on the screen 
     System.Threading.Thread.Sleep(700);   
     Application.Idle += OnLoaded; 
    } 

    private void OnLoaded(object sender, EventArgs e) 
    { 
     Application.Idle -= OnLoaded; 
     _waitForm.Close(); 
    } 
} 

MyWaitForm to nazwa tworzonego formularza, który wygląda jak dialog oczekiwania. Dodałem funkcję SetMessage(), aby dostosować tekst w formularzu oczekiwania.

+0

mówi, że mywaitform nie istnieje – CDrosos

+0

Znalazłem to jako najlepsze podejście, zaprojektowałem własną formę oczekiwania i działa dobrze ... – Bharat

8

Innym sposobem na wyświetlenie ekranu "Ładowanie" tylko w określonym czasie jest umieszczenie go przed zdarzeniem i odrzucenie go po zakończeniu pracy.

Na przykład: chcesz wyświetlić formularz załadunku na razie oszczędności wyniku jako plik MS Excel i odwołuje go po zakończeniu przetwarzania, wykonaj następujące czynności:

LoadingWindow loadingWindow = new LoadingWindow(); 

try 
{ 
    loadingWindow.Show();     
    this.exportToExcelfile(); 
    loadingWindow.Close(); 
} 
catch (Exception ex) 
{ 
    MessageBox.Show("Exception EXPORT: " + ex.Message); 
} 

Albo można umieścić loadingWindow.Close() wewnątrz finally bloku .

+1

to prawie nigdy nie zadziała. Wątek pierwszego planu kontynuuje eksportowanieToExcelFile, gdzie jest zajęty przed wyświetleniem ładowania. – rune711

0

Najlepszym rozwiązaniem, gdy trzeba również animowany obraz jest taki:

1- Musisz utworzyć „WaitForm”, który odbiera metodę, która będzie wykonywana w tle. Jak ten

public partial class WaitForm : Form 
{ 
    private readonly MethodInvoker method; 

    public WaitForm(MethodInvoker action) 
    { 
     InitializeComponent(); 
     method = action; 
    } 

    private void WaitForm_Load(object sender, EventArgs e) 
    { 
     new Thread(() => 
     { 
      method.Invoke(); 
      InvokeAction(this, Dispose); 
     }).Start(); 
    } 

    public static void InvokeAction(Control control, MethodInvoker action) 
    { 
     if (control.InvokeRequired) 
     { 
      control.BeginInvoke(action); 
     } 
     else 
     { 
      action(); 
     } 
    } 
} 

2 - Można użyć Waitform jak ten

private void btnShowWait_Click(object sender, EventArgs e) 
{ 
    new WaitForm(() => /*Simulate long task*/ Thread.Sleep(2000)).ShowDialog(); 
} 
1

kładę trochę animowany gif w postaci zwanej FormWait a potem nazwał ją jako:

// show the form 
new Thread(() => new FormWait().ShowDialog()).Start(); 

// do the heavy stuff here 

// get the form reference back and close it 
FormWait f = new FormWait(); 
f = (FormWait)Application.OpenForms["FormWait"]; 
f.Close(); 
+1

Próbowałem używać tego, ale otrzymuję wyjątek przekroczenia wątku niedozwolone IO. Zmodyfikowałem go, czyniąc go "bezpiecznym dla wątków". Nie jest to najlepsza praktyka, ale dla prostego formularza oczekiwania jest akceptowalna: Zastąp f.Close() z f.Invoke (new ThreadStart (delegate {f.Close();})); –

+0

Dodałem tutaj przetestowane rozwiązanie: https://stackoverflow.com/questions/15769276/best-way-to-display-a-progress-form-while-a-metrical-is-executing-code/45406217# 45406217 – user2288580

0

Cóż, robię coś takiego.

DataTable SLTable = new DataTable(); 
_frmWaitDialog = new NormalWaitDialog(); 
_frmWaitDialog.Shown += async (s, e) => 
{ 
    Refresh(); 
    await Task.Run(() => 
    { 
     //Do your stuff 
    }); 
_frmWaitDialog.Close(); 
}; 
_frmWaitDialog.ShowDialog(this); 
+0

Próbowałem czegoś takiego, ale to powoduje, że moja aplikacja traci ostrość, gdy otwieram ją z połączonego typu pliku w Eksploratorze ... – Nyerguds

Powiązane problemy