Je montre un Forms
fenêtre comme boîte de dialogue
private void buttonOverview_Click(object sender, EventArgs e)
{
(new OverviewBox()).ShowDialog();
MessageBox.Show("Window Exited");
}
OverviewBox
possède une minuterie de rafraîchissement qui est instanciée dans le constructeur.
public OverviewBox()
{
InitializeComponent();
this._polltimer = new Timer { Interval = 30000, Enabled = true };
this._polltimer.Tick += (sender, e) => { this.Poll(); };
}
La méthode Poll
obtient de manière asynchrone des données de la base de données et met à jour la vue sans la geler.
private void Poll()
{
Task.Run(() =>
{
if (!SessionContext.Connectable())
{
return;
}
try
{
[logics to get data]
this.dgvChangeCoordinators.BeginInvoke(new Action(() => { SetDataGridView(this.dataGridView, "<Data Description>", listwithdata); }));
}
catch (Exception ex)
{
Logger.Log(ex.ToString());
throw;
}
});
}
SetDataGridView
définit la liste comme itemsource
d'un datagridview
et affiche la description des données. Parfois cependant, mes utilisateurs se plaignent d'exceptions. Le journal des exceptions ressemble à ceci :
7/15/2013 5:00:10 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
7/15/2013 5:00:23 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
7/15/2013 5:00:40 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
7/15/2013 5:00:53 PM:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at FormulierGenerator.Views.Agent.OverviewBox.<Poll>b__5()
D'après la différence de temps entre les exceptions, je conclus qu'au moins deux instances de la minuterie sont toujours actives (30 secondes entre les sondages, 4 temps différents pour lesquels les groupes de 2 sont dans les 30 secondes, l'intervalle de sondage). Cependant, je ne peux pas simuler le problème en démarrant et en fermant simplement la synthèse deux fois.
Je soupçonne un GC
Un problème connexe se pose lorsque l'objet fenêtre est collecté à un moment donné, mais que le poller continue d'exister. Lorsqu'il tente de mettre à jour la fenêtre dans le contexte du fil de la fenêtre, il échoue. Mais alors, l'objet Window et tout son contenu ne devraient-ils pas exister uniquement dans le contexte de private void ? buttonOverview_Click
? Nous avons ajouté un appel MessageBox.Show() à la méthode du bouton pour tester si la méthode est terminée après la fermeture de la boîte de dialogue. Il s'affiche effectivement.
Définir un point d'arrêt sur le Poll
pour voir si elle était toujours appelée après la fermeture de la boîte de dialogue. C'était le cas, donc le poller vit définitivement plus longtemps que la fenêtre est visible. Ma question est la suivante : mes conclusions sont-elles correctes jusqu'à présent ? Si oui, comment le poller peut-il continuer à exister même si le contexte dans lequel l'objet créant le timer a été instancié n'existe plus, par exemple, comment empêcher le poller de vivre bien après la fermeture de la fenêtre ? Je pense à un événement de déchargement mais je ne sais pas si c'est la meilleure solution.