2010-01-22 9 views
2

J'espère que vous allez bien.Problème avec BeginInvoke (le délégué ne réalise aucune action)

Je suis confronté à un curieux problème avec BeginInvoke et j'ai vraiment vraiment besoin de votre aide!

J'ai une déclaration de classe qui contient plusieurs instances de type rapport

Class Reporting : UserControl 
{ 
    //Reports are inherited from UserControl 
    Report _report1; 
    Report _report2; 
    Report _report3; 

    //Instanciate and return the Report corresponding to the passed ID (The report is 
    //instanciated and created only if it's null) 
    public Report GetReport(int reportId); 

    public delegate void GenerateReportAsImageDelegate(int reportId,string path) 

    //Generate the report and save it as image 
    public void GenerateReportAsImage(int reportId,string path) 
    { 
    if(InvokeRequired) 
    { 
     BeginInvoke(new GenerateReportAsImageDelegate(GenerateReportAsImage),new  object[]{reportId,path}); 

    } 
    else 
    { 
     //... Generating the report etc.. 
    } 
} 

    .... 
} 

Il est un contrôle utilisateur montré sous une forme et ce même usercontrol est également utilisé à partir d'un service Windows pour générer des rapports (et enregistré en tant que l'image) toutes les minutes.

Pour générer un rapport toutes les minutes, j'utilise le System.Threading.Timer.

Voici ce que ma classe générer les rapports ressemble au service:

class ReportServiceClass 
{ 

    Reporting _reportingObject; 
    System.Threading.Timer _timer; 

    Public ReportingServiceClass(int reportId) 
    { 
    _timer = new Timer(new TimerCallback(this.CreateReport), reportId, 0, 1000) 
    } 

    private void CreateReport(Object stateInfo) 
    { 
    int reportId = Convert.ToInt32(stateInfo); 

    //To ensure that the _reportingObject is created on the same thread as the report 
    if(_reportingObject == null) 
     _reportingObject = new _reportingObject(); 

    _reportingObject.GenerateReportAsImage(reportId,@"c:\reports\report.PNG") 
    } 

}

Presque tout fonctionne bien .. excepet que parfois CreateReport est exécuté dans un autre thread du ThreadPool . Ainsi, lorsque j'effectue des actions sur le rapport et ses composants (qui ont été créés dans un autre thread), le paramètre InvokeRequired est défini sur true et tout est évident ... Mais BeginInvoke n'effectue aucune action! C'est presque comme le fil où le rapport a été créé n'existent plus ...

Vous les gars avez des idées sur la façon d'éviter ce problème?

Cela fait maintenant une semaine que je suis confronté à ce problème, j'ai cherché googled et stackoverflowed. mais rien !

Merci beaucoup!

Répondre

1

Je pense que vous utilisez le mauvais Invoke, essayez ceci:

if(this.InvokeRequired) 
{ 
    this.Invoke(new Action<int,string>(GenerateReportAsImage), reportId, path);  
} 
else 
    ... 
0

Ce qui suit est de la documentation ThreadPool.SetMinThreads:

threads inactifs sont maintenus par le pool de threads afin de réduire la temps requis pour satisfaire les demandes de threads de pool de threads. Des minimums séparés sont maintenus pour les threads de travail et les threads d'E/S asynchrones. Les threads inactifs dépassant les minimums sont terminés, pour économiser les ressources système. La maintenance des threads inactifs est une tâche d'arrière-plan. D'après ce que j'ai compris, BeginInvoke et Invoke s'appuient sur la "pompe de message" WinForms pour l'appel réel de votre code. Je n'ai jamais entendu parler de leur utilisation dans un service - il semble que le mécanisme est conçu pour une vraie application WinForms avec une interface utilisateur visible et une pompe de message. Le faire fonctionner de manière fiable dans un service peut être possible - mais il semble que vous devriez au moins créer votre propre thread plutôt que d'utiliser le ThreadPool pour le thread qui crée le UserControl et gère les invocations.

Vous pouvez ou non utiliser Invoke plutôt que BeginInvoke. Le premier est synchrone et le dernier est asynchrone.

+0

Je n'utilise pas explicitement ThreadPool, mais My TimerCallBack a été lancé dans ThreadPool.Je ne sais pas quel est le problème que je dois me concentrer: - Dois-je faire en sorte que mon TimerCallBack est toujours lancé dans le même fil ou - Dois-je pas utiliser BeginInvoke (comme ce mécanisme est conçu pour un vrai formulaire Windows) et de chercher un autre moyen de réaliser des tâches sur mon rapport lorsque CreateReport est exécuté sur un thread différent de celui où le rapport a été créé. – Pato