Question

Tout d'abord, je sais que je devrais utiliser les techniques de Threading appropriées (Threadpool, BeginInvoke, etc.) pour y parvenir, mais c'est un peu au-dessus de ma tête actuellement et il faudra un peu de temps pour en prendre connaissance. matériel et le comprendre (si vous avez des références d’URL pour mon scénario, n'hésitez pas à le poster).

Entre-temps, j'utilise backgroundWorker pour extraire un très grand jeu de résultats et y remplir un DatagridView. J'ai réussi à créer un SortableBindingList<TEntities> dans mon événement DoWork et à le transmettre dans le résultat. Et dans le RunWorkerCompleted événement, je jette et lie ce List<long> à ma grille. Mes deux principaux domaines de préoccupation sont les suivants:

1) Accès aux variables privées. Je souhaite transmettre l'un des deux paramètres DoWork à mon événement SortableBindingList<Task>, mais exécuter une requête différente en fonction de la liste qui lui a été transmise. Je peux contourner cela en déclarant une variable booléenne privée au niveau de la classe qui agit comme un drapeau. Cela semble ridicule de demander, mais dans mon CellFormatting, puis-je accéder à cette variable privée et acheminer la requête en conséquence? (J'ai testé cela et cela fonctionne, sans qu'aucune erreur ne survienne)

private bool SearchEngaged = false;

private void bgw_DoWork(object sender, DoWorkEventArgs e) {
    BackgroundWorker worker = sender as BackgroundWorker;
    e.Result = GetTasks((List<long>)e.Argument, worker, e);
}
SortableBindingList<Task> GetTasks(List<long> argsList, BackgroundWorker worker, DoWorkEventArgs e) {
    SortableBindingList<Task> sbl = null;
    if (worker.CancellationPending) {
        e.Cancel = true;
    }
    else {
        if (SearchEngaged) {
            sbl = DU.GetTasksByKeys(argsList);
        }
        else {
            sbl = DU.GetTasksByDivision(argsList);
        }
    }
    return sbl;
}

2) Le fil d'interface utilisateur se fige au début de RunWorkerCompleted. Ok, je sais que mon interface utilisateur est réactive pendant l'événement <=>, car il faut +/- 2 secondes pour s'exécuter et retourner mon <=> si je ne lie pas la liste à la grille. , mais simplement le peupler. Cependant, mon interface utilisateur se fige lorsque je lie cela à la grille, ce que je fais dans l'événement <=>. N'oubliez pas que ma grille comporte 4 colonnes d'image que je gère dans <=>. Ce processus nécessite 8 secondes supplémentaires, au cours desquelles mon interface utilisateur est totalement non interactive. Je suis conscient des implications inter-threads que cela implique, mais puis-je obtenir le peuplement et le formatage de la grille en arrière-plan ou sans que mon interface utilisateur ne se fige ? RunWorkeCompleted ressemble à ceci:

private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
    if (e.Cancelled) {
        lblStatus.Text = "Operation was cancelled";
    }
    else if (e.Error != null) {
        lblStatus.Text = string.Format("Error: {0}", e.Error.Message);
    }
    else {
        SortableBindingList<Task> sblResult = (SortableBindingList<Task>)e.Result;
        dgv.DataSource = sblResult;
        dgv.Enabled = true;
        TimeSpan Duration = DateTime.Now.TimeOfDay - DurationStart;
        lblStatus.Text = string.Format("Displaying {0} {1}", sblResult.Count, "Tasks");
        lblDuration.Visible = true;
        lblDuration.Text = string.Format("(data retrieved in {0} seconds)", Math.Round(Duration.TotalSeconds, 2));
        cmdAsyncCancel.Visible = false;
        tmrProgressUpdate.Stop();
        tmrProgressUpdate.Enabled = false;
        pbStatus.Visible = false;
    }
}

Désolé pour la longue requête, mais j'apprécierai vraiment vos réponses! merci!

Était-ce utile?

La solution

Votre code semble faire exactement ce qu'il faut.

En ce qui concerne les 8 secondes nécessaires à la mise à jour de l'écran par le thread d'interface utilisateur, vous ne pouvez rien faire à ce sujet. Voir ma réponse à cette question .

Pour optimiser la partie de l'interface utilisateur, essayez d'appeler SuspendLayout et ResumeLayout sur la grille ou son panneau contenant.

Vous pouvez également essayer de réduire le nombre de traitements effectués lors de la liaison de données. Par exemple:

  • Les calculs effectués dans la grille peuvent être déplacés dans le modèle de données (et donc dans le thread de travail).
  • Si la grille calcule automatiquement ses colonnes en fonction du modèle de données, essayez plutôt de les coder en dur.
  • MODIFIER: effectuez une page sur les données de la couche de gestion et indiquez dans la grille uniquement un petit nombre de lignes à la fois.

Autres conseils

Je pense que la solution la plus simple à votre problème consiste à définir la source de données de votre grille entre DoWork au lieu de RunWorkerCompleted en utilisant Dispatcher.BeginInvoke ce que vous avez mentionné vous-même. Quelque chose comme ça:

private bool SearchEngaged = false;

private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    SortableBindingList<Task> sblResult = GetTasks((List<long>)e.Argument, worker, e);

    BeginInvoke((Action<object>)(o => dataGridView1.DataSource = o), sblResult);
}

private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled) {
        lblStatus.Text = "Operation was cancelled";
    }
    else if (e.Error != null) {
        lblStatus.Text = string.Format("Error: {0}", e.Error.Message);
    }
    else
    {
        dgv.Enabled = true;
        TimeSpan Duration = DateTime.Now.TimeOfDay - DurationStart;
        lblStatus.Text = string.Format("Displaying {0} {1}", sblResult.Count, "Tasks");
        lblDuration.Visible = true;
        lblDuration.Text = string.Format("(data retrieved in {0} seconds)", Math.Round(Duration.TotalSeconds, 2));
        cmdAsyncCancel.Visible = false;
        tmrProgressUpdate.Stop();
        tmrProgressUpdate.Enabled = false;
        pbStatus.Visible = false;
    }
}

En ce qui concerne la question de la variable privée, je ne pense pas que ce sera un problème dans votre cas. Si vous le modifiez à l'aide d'un événement d'interface utilisateur, il suffit de marquer le champ privé comme volatile. La documentation du <=> mot clé peut être trouvée ici:

http://msdn.microsoft.com/en-us/library /x13ttww7.aspx

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top