2009-03-05 2 views
4

Je souhaite démarrer un travail dans un nouveau thread ou utiliser un arrière-plan pour le faire, mais je n'ai jamais fait cela auparavant et je ne vous demande pas comment je devrais le faire.Exécution de la classe en tant que nouveau thread

Mon programme a un datagridview avec une liste de fichiers, un fichier par ligne. Je souhaite que l'utilisateur puisse sélectionner une ligne, puis appuyer sur "Démarrer le téléchargement" pour démarrer un travail d'arrière-plan du téléchargement. Je veux récupérer les événements de la progression du téléchargement.

J'ai une classe clsDownload qui gère tout et soulève des événements, mais comment puis-je implémenter le travail en arrière-plan?

Dois-je utiliser System.ComponentModel.BackgroundWorker à l'intérieur de la classe ou créer un wrapper qui gère cela ou utiliser d'autres éléments de thread?

Merci.

Modifier: Je ne comprends pas comment implémenter mon téléchargement dans le backgroundworker, tout petit exemple serait très agréable. L'exemple sur msdn ne m'a pas loin.

J'ai une classe de téléchargement qui a une fonction StartDownload. Dois-je utiliser l'arrière-plan dans la classe ou dans l'appelant? "se sentir stupide"

Répondre

1

J'ai créé plusieurs classes différentes qui incorporent BackgroundWorker. Ce que je fais généralement est d'avoir un composant BackgroundWorker sur le formulaire qui sera ouvert lorsque le travail est en cours d'exécution, puis je passe cette instance au constructeur de ma classe d'emplois.

Voici ce que votre classe d'emplois pourrait ressembler à:

Private m_bwMain As BackgroundWorker 

Public Sub New(ByVal bwMain As BackgroundWorker) 
    m_bwMain = bwMain 

    'additional setup code here 
End Sub 

Pour démarrer un emploi, vous feriez quelque chose comme ça dans le gestionnaire d'événements Click de votre bouton Démarrer Télécharger:

lblStatus.Text = "Initializing ..." 
bgwMain.RunWorkerAsync(someFileName) 

Je déclare ma classe de travail en tant que membre privé du formulaire en cours, puis l'instancie dans l'événement BackgroundWorker.DoWork. De là, vous pouvez appeler votre méthode pour télécharger un fichier:

Private Sub bgwMain_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwMain.DoWork 
    m_oJobEngine = New JobEngine(CType(sender, BackgroundWorker)) 
    m_oJobEngine.DownloadFile(CStr(e.Argument)) 
End Sub 

Pour signaler des progrès à l'utilisateur, vous pouvez gérer les événements déclenchés par votre classe dans votre principale forme. Vous devez juste vous assurer que la déclaration de l'objet de classe de travail a le mot clé WithEvents. À partir de ces gestionnaires, vous pouvez appeler la méthode ReportProgress de BackgroundWorker. Depuis ReportProgress, vous pouvez apporter les modifications nécessaires à l'interface utilisateur pour indiquer la progression. Voici un exemple:

Private Sub m_oJobEngine.DownloadProgress(ByVal bgw as Backgroundworker, ByVal bytesTransferred as Long) Handles m_oJobEngine.DownloadProgress 
    bgw.ReportProgress(0, bytesTransferred) 
End Sub 
Private Sub bgwMain_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgwMain.ProgressChanged 
    lblStatus.Text = CLng(e.UserState).ToString & " bytes transferred." 
End Sub 

Espérons que cela aide.

0

L'arrière-plan semble fonctionner correctement ... Il existe un exemple sur MSDN.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Ou vous pourriez faire quelque chose comme:

WaitCallBack workCallBack= new WaitCallBack(DownloadMethod); 
if(!ThreadPool.QueueUserWorkItem(workCallBack, "ThreadPooled") 
{ 
    // Unable to Pool 
} 

// Work has been added to pool and will execute when possible 

paramètres dépend de ce que le cas échéant vous avez besoin pour le fil.

+0

Je déconseille WaitCallback car il est plus difficile de renvoyer des événements au thread d'interface utilisateur (ce que je suppose est quelque chose qu'il veut accomplir). – Inferis

3

Si vous ne faites que le téléchargement et que vous n'avez pas besoin d'un autre traitement asynchrone, vous pouvez simplement utiliser les méthodes asynchrones de la classe WebClient. Bien que vous ayez déjà votre propre cours, ce n'est probablement pas une solution pour vous.

Sinon, vous pouvez utiliser BackgroundWorker comme vous l'avez mentionné. La page MSDN a un exemple comment le faire.

EDIT: L'histoire courte est:

  • Vous créez le BackgroundWorker de l'appelant;
  • Lorsque vous souhaitez démarrer le travail d'arrière-plan, vous appelez BackgroundWorker.RunWorkerAsync;
  • dans le gestionnaire d'événements DoWork vous effectuez le travail en arrière-plan, dans votre cas, vous démarrez votre classe de téléchargement; Pendant que vous faites le travail en arrière-plan, vous devez vérifier de temps en temps pour CancelationPending;
  • Lorsque vous souhaitez signaler un avancement, vous devez le calculer en pourcentage et appeler ReportProgress.

Et si vous avez besoin de quelque chose de vraiment personnalisé, vous pouvez toujours créer le vôtre Thread. Je voudrais personnellement rester avec BackgroundWorker. Il a un bon ensemble de notifications pour les différentes étapes du travail.Si vous utilisez Thread, vous devrez les implémenter vous-même.

Je voudrais également m'assurer que le code ne crée pas trop d'instances. Vous voulez limiter le nombre de téléchargements concurent et mettre en file d'attente tout ce qui dépasse ce nombre.

+0

Im utilisant webservices et MTOM pour obtenir de gros fichiers à partir d'un serveur, donc je ne peux pas co avec WebClient. – Stefan

+0

Dans ce cas, générez des méthodes asynchrones sur votre référence de service et utilisez-les. – Inferis

+0

@inferis - Les méthodes asynchrones sur le webservice ne fournissent pas de notifications sur les progrès. –

3

Je vous recommande fortement BackgroundWorker si vous avez besoin de fournir des commentaires à l'utilisateur sur l'interface utilisateur. Les événements ProgressChanged et RunWorkerCompleted sont exécutés sur le thread de l'interface utilisateur. Il n'est donc pas nécessaire de procéder au marshaling, ce qui peut compliquer le code.

+0

Bonjour @ user927258, évitez les modifications mineures. Voir: http://meta.stackexchange.com/questions/180545/mass-editing-existing-answers-with-a-similar-pattern – yannis

+0

@Inferis bien. – vasanth

0

La classe qui utilise clsDownload (probablement votre classe Form) doit utiliser BackgroundWorker pour exécuter la méthode de téléchargement.