2013-03-14 14 views
5

W mojej aplikacji wpf (C#) długi proces wykonywany jest po naciśnięciu przycisku przez użytkownika. Po naciśnięciu przycisku do momentu zakończenia całego kodu okno zamarza, a użytkownik nie może wykonać żadnego innego zadania w oknie. W jaki sposób mogę uczynić kod kliknięcia przycisku jako proces w tle, aby okno stało się responsywne dla użytkownika. Próbowałem następującej metody, ale nie udało się.Spraw, aby wpf odpowiadał UI po kliknięciu przycisku

private void btn_convert_Click(object sender, RoutedEventArgs e) 
{ 
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 
    new Action(() => { 

     WorkerMethod(); 
    })); 
} 

Gdzie WorkerMethod jest funkcją z całym kodem. Wszelkie sugestie.

Pozdrawiam,
Sangeetha

Odpowiedz

5

Co masz faktycznie zrobić tutaj prosi wątku UI, aby uruchomić ciężkie zadanie . przez dyspozytora

należy utworzyć nowy wątek/zadanie i niech go uruchomić metodę tła:

Thread t = new Thread(() => WorkerMethod()); 
t.Start(); 

celu uzyskania dalszych informacji przeczytać:

WPF BackgroundWorker vs. Dispatcher

Understanding “Dispatcher” in WPF

+1

To rozwiązanie działa dobrze, ale z wyjątkiem. W metodzie pracy mam kod wyłączania włączania przycisku, który daje wyjątek, wątek wywołujący nie może uzyskać dostępu do tego obiektu, ponieważ inny wątek jest jego właścicielem. – Sangeetha

+0

@Sangeetha używać Dispatchera do włączania/wyłączania ONL – makc

1

Jesteś wywołanie metody na UI-Dispatcher, uczyni to zamrożenie UI. Utwórz nowy wątek w swojej click-zdarzenia, używając

private void btn_convert_Click(object sender, RoutedEventArgs e) 
    { 
     Thread t = new Thread(new ThreadStart(WorkerMethod)); 
     //assign STA or MTA, etc.... 
     t.Start(); 
    } 

Look here celu uzyskania informacji na temat „System.Threading.Thread`.

+0

W workmethod mam przycisk włączyć wyłączyć kod, który daje wyjątek, wątek wywołujący nie ma dostępu do tego obiektu, ponieważ inny wątek jest jej właścicielem. – Sangeetha

+1

@Sangeetha Musisz umieścić w kolejce swoje żądanie w kolejce UI-Dispatchera. Spójrz [tutaj] (http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherobject.checkaccess.aspx) i postępuj zgodnie z ilustracją. –

7

Alternatywą do odpowiedzi o to BackgroundWorker. Ma dodatkową zaletę, że powraca do wątku GUI po zakończeniu.

private void btn_convert_Click(object sender, RoutedEventArgs e) 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    worker.DoWork += WorkerMethod; 
    worker.RunWorkerCompleted += WorkerEnded; 
    worker.RunWorkerAsync(); 
} 

private void WorkerMethod() 
{ 
    // New thread, cannot access GUI 
} 

private void WorkerEnded() 
{ 
    // Back on the GUI Thread 
    // Worker is finished 
} 
+0

Jestem nowy w gwintowaniu, Znajdź to proste i jasne, aby zrozumieć – Karthik

0

Spróbuj użyć klasy Backgroundworker. Musisz zarejestrować się w zdarzeniu DoWork i utworzyć procedurę obsługi zdarzeń, w której umieścisz cały kod przetwarzania. Uruchomienie procesu roboczego za pomocą metody RunWorkerAsync. Istnieje również metoda, która może raportować postępy Twoich pracowników "ReportProgress". RunWorkerCompleted pokaże ci, kiedy twój robot przetwarza twój kod. Spróbuj się znaleźć w internecie po BackgroundWorker a znajdziesz mnóstwo przykładów, jak go używać

10

Jeśli kierowanie .NET 4.5, można użyć async/await aby Twoje UI reaguje:

private async void btn_convert_Click(object sender, RoutedEventArgs e) 
{ 
    await WorkerMethod(); 
} 

zmodyfikować WorkerMethod:

private Task WorkerMethod() 
{ 
    return Task.Run(() => 
     { 
      // your long running task here 
     }); 
} 
+2

Czy możesz wyjaśnić ten kod, proszę? Co robią słowa kluczowe asynchroniczne i oczekujące? – Doug

1

sobie wyobrazić inny sposób jestem bardzo dumny: W przypadku, gdy multithread mieć korzyści wyłącznie w celu umożliwienia IHM animować pasek postępu, jeśli użytkownik nie ma interakcji z t hemm podczas procesu lub po prostu, jeśli nie ma czasu na tworzenie wielowątkowości i nie możesz zezwolić aplikacji na zamrożenie bez informacji zwrotnej:

możesz rozwinąć moduł ładujący uruchamiany w innym wątku STA, który utworzył inne okno i wyświetla ten moduł ładujący w środek zamrożonego okna.

Oto post z którego zrobiłem artykuł i implementację takiego rozwiązania:

http://charly-studio.com/blog/a-loader-for-wpf-long-ui-process/

Oto jak mogę używać komponent:

private void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
{ 
    // Long UI process context 
    using (new LongUIProcessContext("Wait while loading...")) 
    { 
     Thread.Sleep(2000); 

     // Sub long ui process context 
     using (new LongUIProcessContext("Wait while loading 2...")) 
     { 
      Thread.Sleep(2000); 
     } 

     // Another sub long ui process context 
     using (new LongUIProcessContext("Wait while loading 3...")) 
     { 
      Thread.Sleep(2000); 
     } 
    } 
} 

i tu jest proponowana przeze mnie ławka wygląda następująco: long Ui process bench

A tutaj jest bezpośredni link do ławki Zrobiłem w którym można odnaleźć elementy:

The bench solution direct download

Powiązane problemy