Compact Framework/Threading - Mesajul MessageBox se afișează peste alte controale după alegerea opțiunii

Lucrez la o aplicație care captează și instalează o grămadă de actualizări de pe un server extern și are nevoie de ajutor pentru filetare. Utilizatorul urmărește acest proces:

  • Butonul de clicuri
  • Metoda verifică pentru actualizări, numărul este returnat.
  • Dacă este mai mare de 0, întrebați utilizatorul dacă doriți să instalați utilizând MessageBox.Show ().
  • Dacă da, acesta rulează printr-o buclă și sună BeginInvoke() pe metoda run() a fiecărei actualizări pentru ao rula în fundal.
  • Clasa de actualizare are câteva evenimente care sunt utilizate pentru actualizarea unei bare de progres etc.

Actualizările pentru bara de progres sunt bine, dar MessageBox-ul nu este complet eliminat de pe ecran, deoarece bucla de actualizare începe imediat după ce utilizatorul dă clic pe da (a se vedea imaginea de mai jos).

  • Ce ar trebui să fac pentru a face ca mesajul să dispară instantaneu înainte de începerea ciclului de actualizare?
  • Ar trebui să folosesc fire în loc de BeginInvoke ()?
  • Ar trebui să efectuez verificarea inițială a unui thread separat și să sun din mesajul MessageBox.Show() din acel fir?

Cod

// Button clicked event handler code...
DialogResult dlgRes = MessageBox.Show(
    string.Format("There are {0} updates available.\n\nInstall these now?", 
    um2.Updates.Count), "Updates Available", 
    MessageBoxButtons.YesNo, 
    MessageBoxIcon.Question, 
    MessageBoxDefaultButton.Button2
);

if (dlgRes == DialogResult.Yes)
{
    ProcessAllUpdates(um2); 
}

// Processes a bunch of items in a loop
private void ProcessAllUpdates(UpdateManager2 um2)
{
    for (int i = 0; i < um2.Updates.Count; i++)
    {
        Update2 update = um2.Updates[i];

        ProcessSingleUpdate(update);

        int percentComplete = Utilities.CalculatePercentCompleted(i, um2.Updates.Count);

        UpdateOverallProgress(percentComplete);
    }
}

// Process a single update with IAsyncResult
private void ProcessSingleUpdate(Update2 update)
{
    update.Action.OnStart += Action_OnStart;
    update.Action.OnProgress += Action_OnProgress;
    update.Action.OnCompletion += Action_OnCompletion;

    //synchronous
    //update.Action.Run();

   //async
    IAsyncResult ar = this.BeginInvoke((MethodInvoker)delegate() { update.Action.Run(); });
}

Screenshot

Windows Mobile Bug

0
fr hi bn

3 răspunsuri

Ați încercat să puneți a

Application.DoEvents()

aici

if (dlgRes == DialogResult.Yes)
{
   Application.DoEvents(); 
   ProcessAllUpdates(um2); 
}
0
adăugat

Interfața dvs. UI nu se actualizează, deoarece toate lucrările se întâmplă în interfața cu utilizatorul. Apelul dvs. către:

this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); }) 

se spune invocare update.Action.Run() pe firul care a creat "this" (formularul dvs.), care este thread-ul interfeței cu utilizatorul.

Application.DoEvents()

va da într-adevăr thread-ul UI șansa de a redraw ecran, dar aș fi tentat să creeze un nou delegat, și apela BeginInvoke pe asta.

Aceasta va executa funcția update.Action.Run() pe un fir separat alocat din grupul de fire. Puteți continua să verificați IAsyncResult până când actualizarea este completă, interogând obiectul de actualizare pentru progresul său după fiecare verificare (deoarece nu puteți avea celălalt fir de actualizare a barei de progres/UI), apoi apelați Application.DoEvents ().

De asemenea, trebuie să apelați la EndInvoke (), în caz contrar s-ar putea să ajungeți la scurgeri de resurse

Aș fi, de asemenea, tentat să pun un buton de anulare în dialogul de progres și să adaug un timeout, în caz contrar dacă actualizarea se blochează (sau durează prea mult), atunci aplicația dvs. va fi blocată pentru totdeauna.

0
adăugat

@ John Sibly

Puteți să scăpiți cu nu apelați EndInvoke atunci când se ocupă de WinForms fără consecințe negative

Singura excepție documentată de la regula despre care știu este în Windows Forms, în care ți se permite în mod oficial să suni Control.BeginInvoke fără a te deranja să apelezi Control.EndInvoke.

Cu toate acestea, în toate celelalte cazuri, atunci când se ocupă de modelul Begin/End Async, trebuie să presupuiți că se va scurge, așa cum ați afirmat.

0
adăugat