Idéalement, vous voudriez enregistrer vos formulaires en tant que Singleton
. Cependant, d'après mon expérience, cela donne lieu à des erreurs difficiles à déboguer, en particulier lorsque vous utilisez une fonction BindingSource
pour lier vos données à quoi que ce soit.
Un deuxième problème lié à l'utilisation de Singleton
car le style de vie est que si votre application utilise des fenêtres sans modèle, cette fenêtre lancera un message d'erreur. ObjectDisposedException
lorsqu'il est ouvert une seconde fois, car le cadre d'application Windows Forms se débarrasse du formulaire à la première fermeture, alors que Simple Injector devrait s'en charger. Donc Simple Injector créera une - et exactement une - instance, s'il est enregistré comme Singleton. Si quelqu'un d'autre (par exemple votre application, le framework Windows Forms) dispose de l'objet, il ne sera pas recréé.
La solution la plus simple, qui est également facile à comprendre, consiste à enregistrer vos formulaires en tant que Transient
. Et oui, vous devez supprimer les avertissements de diagnostic. La raison de cet avertissement de diagnostic selon le documentation :
Un composant qui implémente IDisposable aurait généralement besoin d'un nettoyage déterministe, mais Simple Injector ne suit pas et ne dispose pas implicitement des composants enregistrés avec le style de vie transitoire.
Simple Injector est incapable de se débarrasser d'un composant transitoire car il ne peut pas déterminer quand l'objet doit être éliminé. Cela signifie toutefois que les formulaires qui sont ouverts de manière modale avec un appel à '.ShowDialog()' ne seront jamais éliminés ! Et comme une application Windows Forms fonctionne généralement pendant une longue période, voire une semaine ou un mois, il en résultera éventuellement un Win32Exception avec un message : "Error Creating Window Handle". Ce qui signifie essentiellement que vous avez épuisé toutes les ressources de l'ordinateur.
L'élimination des formulaires est donc importante. Et bien que Simple Injector soit capable de faire ce travail si vous utilisiez un fichier Portée Avec Windows Forms, ce n'est pas si facile à mettre en œuvre. Vous devez donc vous charger vous-même de disposer des formulaires fermés qui ont été affichés à l'aide de l'option ShowDialog()
.
En fonction de votre cas d'utilisation spécifique, il existe plusieurs façons de mettre en œuvre un système de gestion de l'information. FormOpener
o NavigationService
. Une façon de le faire :
public interface IFormOpener
{
void ShowModelessForm<TForm>() where TForm : Form;
DialogResult ShowModalForm<TForm>() where TForm : Form;
}
public class FormOpener : IFormOpener
{
private readonly Container container;
private readonly Dictionary<Type, Form> openedForms;
public FormOpener(Container container)
{
this.container = container;
this.openedForms = new Dictionary<Type, Form>();
}
public void ShowModelessForm<TForm>() where TForm : Form
{
Form form;
if (this.openedForms.ContainsKey(typeof(TForm)))
{
// a form can be held open in the background, somewhat like
// singleton behavior, and reopened/reshown this way
// when a form is 'closed' using form.Hide()
form = this.openedForms[typeof(TForm)];
}
else
{
form = this.GetForm<TForm>();
this.openedForms.Add(form.GetType(), form);
// the form will be closed and disposed when form.Closed is called
// Remove it from the cached instances so it can be recreated
form.Closed += (s, e) => this.openedForms.Remove(form.GetType());
}
form.Show();
}
public DialogResult ShowModalForm<TForm>() where TForm : Form
{
using (var form = this.GetForm<TForm>())
{
return form.ShowDialog();
}
}
private Form GetForm<TForm>() where TForm : Form
{
return this.container.GetInstance<TForm>();
}
}
Cette classe doit être enregistrée comme Singleton
:
container.RegisterSingleton<IFormOpener, FormOpener>();
Et peut être utilisé en injectant ce service dans par exemple votre formulaire Root de l'application :
public partial class RootForm : Form
{
private readonly IFormOpener formOpener;
public RootForm(IFormOpener formOpener)
{
this.formOpener = formOpener;
this.InitializeComponent();
}
private void ShowCustomers_Click(object sender, EventArgs e)
{
this.formOpener.ShowModelessForm<AllCustomersForm>();
}
private void EditCustomer_Click(object sender, EventArgs e)
{
var result = this.formOpener.ShowModalForm<EditCustomerForm>();
// do something with result
}
}