2014-04-29 12 views
11

Użyłem kawałek prostego kodu z tego pomocnego postProste BackgroundWorker nie aktualizuje etykietę na stronie internetowej

Wykorzystuje przycisk i etykietę, etykieta powinna zgłosić „10% zakończone” ... " 20% ukończone "... i tak dalej.

Kiedy debuguję, kod jest trafiony, ale moja etykieta nie aktualizuje się w przeglądarce.

Próbowałem z & bez paneli aktualizacji, zi bez strony wzorcowej.

protected void btnStartThread_Click(object sender, EventArgs e) 
    { 
     BackgroundWorker bw = new BackgroundWorker(); 

     // this allows our worker to report progress during work 
     bw.WorkerReportsProgress = true; 

     // what to do in the background thread 
     bw.DoWork += new DoWorkEventHandler(delegate(object o, DoWorkEventArgs args) 
     { 
      BackgroundWorker b = o as BackgroundWorker; 

      // do some simple processing for 10 seconds 
      for (int i = 1; i <= 10; i++) 
      { 
       // report the progress in percent 
       b.ReportProgress(i * 10); 
       Thread.Sleep(1000); 
      } 
     }); 



     // what to do when progress changed (update the progress bar for example) 
     bw.ProgressChanged += new ProgressChangedEventHandler(delegate(object o, ProgressChangedEventArgs args) 
     { 
      label1.Text = string.Format("{0}% Completed", args.ProgressPercentage); 
     }); 


     // what to do when worker completes its task (notify the user) 
     bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
     delegate(object o, RunWorkerCompletedEventArgs args) 
     { 
      label1.Text = "Finished!"; 
     }); 

     bw.RunWorkerAsync(); 
+9

Jeśli kod HTML został już wysłany do klienta przez sieć, jak można go zaktualizować? Aby zaktualizować stronę, musisz używać AJAX na kliencie. –

+0

Z tego powodu pomyślałem, że menedżer skryptów i panel aktualizacji na stronie mógłby załatwić sprawę:/ – wotney

+0

Powinien. Nie pamiętam całkowicie, czy na pewno nie musisz wywoływać czegoś takiego jak updatePanel.Update(); lub podobne? – Falgantil

Odpowiedz

5

potencjalnie można zrobić długie odpytywanie, aby uzyskać zaktualizowany wynik. Osobiście nie użyłbym pracownika tła w aplikacji sieciowej. Rozważ także spojrzenie na SignalR, zdarzenia wysłane przez serwer i Async and Await lub Task Parallel Library.

+0

Trochę pomocny, ale nie za duży wybór. Naprawdę muszę dowiedzieć się, jak uzyskać aktualizacje na stronie internetowej, z powrotem do użytkownika, w trakcie długiego działania. – AgapwIesu

4

BackgroundWorker nie jest odpowiedni dla ASP.NET i nie działa z ASP.NET bardzo dobrze, ponieważ ASP.NET działa na modelu żądania/odpowiedzi. Aby otrzymywać aktualizacje, przeglądarka klienta musi zażądać informacji z serwera. Na przykład, aby zaktualizować swoją Label, musisz wysłać do serwera żądanie nowej wartości.

Jedną z opcji może być użycie AJAX do tego celu na kliencie, aby zaktualizować stronę. Ale zamiast używać formalnego AJAX, możesz użyć iframe, który jest świetnym sposobem na asynchroniczne wykonywanie długotrwałego procesu, bez uzależnienia od żadnej konkretnej architektury AJAX. Po kliknięciu przycisku, niewidzialna iframe dynamicznie generowane i wykorzystywane do wykonywania LongRunningProcess.aspx w tle:

<head runat="server"> 
<script type="text/javascript"> 
    function BeginProcess() { 
     var iframe = document.createElement("iframe"); 
     iframe.src = "LongRunningProcess.aspx"; 
     iframe.style.display = "none"; 
     document.body.appendChild(iframe); 
     document.getElementById('trigger').disabled = true; 
    } 

    function UpdateProgress(PercentComplete, Message) { 
     document.getElementById('<%= Label1.ClientID %>').innerHTML = PercentComplete + '% ' + Message; 
} 
</script> 
</head> 

<body> 
    <form id="form1" runat="server"> 
    <div> 
    <input type="submit" value="Start Long Running Process" id="trigger" 
     onclick="BeginProcess(); return false;" style="width: 185px;"/> 
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label> 
    </div> 
    </form> 
</body> 

I LongRunningProcess.aspx.cs:

protected void Page_Load(object sender, EventArgs e) 
{ 
    for (int i = 1; i <= 9; i++) 
    { 
     UpdateProgress(i * 10, " Completed."); 
     System.Threading.Thread.Sleep(1000); 
    } 
    UpdateProgress(100, "Finished!"); 
} 

protected void UpdateProgress(int PercentComplete, string Message) 
{ 
    Response.Write(String.Format("<script type=\"text/javascript\">parent.UpdateProgress({0}, '{1}');</script>", PercentComplete, Message)); 
    Response.Flush(); 
} 

można zobaczyć wynik, a także dowiedzieć się więcej w Dave Warda świetny artykuł tutaj: Easy incremental status updates for long requests.

3

Jest to rzadkie, ale .NET może czasami uruchamiać zadania asynchroniczne synchronicznie (nie wynika to z dokumentacji na MSDN, gdy może się tak zdarzyć), ale jeśli tak się dzieje w twoim przypadku, zablokuje to pętlę wiadomości w twojej aplikacji WinForm.

Aby przetestować tę teorię, można spróbować użyć wywołania Application.DoEvents() w procedurze obsługi ProgressChanged i instrukcji DoWork i sprawdzić, czy to pomaga. To brzydka praca, ale powinna wymusić aktualizację interfejsu, jeśli disptacher wykonuje synchronicznie swoje zadania.

+0

To jest Web Forms, a nie Windows Forms, podobno. – areyesram

2

Masz zasadniczo dwie opcje.

Po jednym, można pobierać z przeglądarki przeglądarkę, aby uzyskać aktualny procent za pomocą JavaScript. setInterval jest oczywistą metodą do użycia i można użyć jQuery lub podobnego do wywoływania AJAX na twój serwer. Jest to jednak trochę nieefektywne, ponieważ twój serwer brzmi, jakby wiedział, kiedy robi postępy lub robi, więc serwer powinien podnosić zdarzenia.

Dwa, które jest bardziej, czego chcesz, to użycie SignalR. Masz ustawienia skonfigurowane do "wypychania" z serwera, ponieważ zdarzenia dotyczące czasu są podnoszone, ale nie ma prostego sposobu, aby to zrobić w HTTP (HTML5 WebSockets są również alternatywą). Korzystanie z technologii serwerowej, takiej jak SignalR, pozwala tworzyć "huby", które podnoszą zdarzenia do klientów. Mogą to być konkretne zdarzenia skierowane do użytkownika lub wszystkie typy klientów - do Ciebie.

Zobacz tutaj wstęp/prezentacje. Zrobili dość trudny problem dość łatwo: http://www.asp.net/signalr

Również, jak wspomniano przez innych, prawdopodobnie nie chcesz używać BackgroundWorker. Wypróbuj QueueBackgroundWorkItem. http://blogs.msdn.com/b/webdev/archive/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-long-background-process-in-asp-net.aspx