Documentation
Documentation copied to clipboard
Windows form how to call forms correctly from container
I've registered my FormUserNew:
_container.Register<FormUsersNew>();
which is called from FormMain (starting form), however i am not sure how should i take instance of that in FormMain then call it.
Here's my code below:
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(_container.GetInstance<FormMain>());
private static void Bootstrap()
{
_container = new Container();
_container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
_container.Register<IUserService, UserService>(Lifestyle.Scoped);
_container.Register<IUserTypeService, UserTypeService>(Lifestyle.Scoped);
_container.Register<FormMain>();
_container.Register<FormUsersNew>(); //<=========== form
_container.Verify();
}
}
FormUsersNew:
public partial class FormUsersNew
{
private readonly Sektor _sektor;
private readonly IUserService _userService;
private readonly IUserTypeService _userTypeService;
public FormUsersNew(IUserService userService, IUserTypeService userTypeService, EnumSector sector)
{
InitializeComponent();
_sektor = sektor;
_userService = userService;
_userTypeService = userTypeService;
}
How then to call FormUsersNew to use my dependencies from container? :
public partial class FormMain
{
private void BtnOpen_Click(object sender, EventArgs e)
{
//call FormUserNew from container <=======================
//var form = new FormUsersNew();
//form.ShowDialog();
}
}
What you can try is hiding the management around showing (and disposing) your forms behind an abstraction. For instance:
public partial class FormMain
{
private IFormManager manager;
public FormMain(IFormManager m) => manager = m;
private void BtnOpen_Click(object sender, EventArgs e)
{
this.manager.ShowDialog<FormUsetsNew>();
}
}
Such manager can be implemented as follows:
class Manager : IFormManager
{
private Container container;
public Manager(Container c) => container = c;
public void ShowDialog<TForm>()
where TForm : Form
{
using (var form = container.GetInstance<TForm>())
{
form.ShowDialog();
}
}
}
I'm sure @TheBigRic can give you a more detailed, and better, answer.
hmm, and what about if another form is called from FormUserNew so we would have chain like: FormMain (starting form) --> FormUserNew --> FormOther (how handle this form?)
I was also thinking about instead forms having their dependencies inside constructor to have dependencies as properties and in constuctor body give default dependency value - what about that? in this case i don;t need to give form;s constructor arguments but still can test in unit tests. What you think?
P.S How it's accmomplished in WPF ? If not mistaken there is also main form so same workaround could be done?
what about if another form is called from FormUserNew so we would have chain like: FormMain (starting form) --> FormUserNew --> FormOther (how handle this form?)
In that case you would inject IFormManager in FormUserNew as well.
How it's accmomplished in WPF ? If not mistaken there is also main form so same workaround could be done?
I've actually written how to integrate with UWP in my book, which is very similar to WPF. You can read the section about UWP online here. Manning allows you to read part of that section for free, so it might be enough to get started.
I once wrote an answer on stack overflow with a very similar but more complete IFormManager although I called it IFormOpener. You can find this here
hmm, and what about if another form is called from FormUserNew so we would have chain like: FormMain (starting form) --> FormUserNew --> FormOther (how handle this form?)
You can use the same IFormOpener/IFormManager. I think however from a users point of view showing multiple screens with subtasks should avoided. Try to show a main screen with views of data and modal screens on top to edit or create new data. This screens could be build up from multiple usercontrols to get a good separation.
I was also thinking about instead forms having their dependencies inside constructor to have dependencies as properties and in constuctor body give default dependency value - what about that?
Why? The Windows Forms Designer can handle a non default ctor pretty well. So don't do this, you do not need it I think.
@TheBigRic I have to more questions:
1. Let's say there is one constructor parameter for some form besides normal dependencies. How can i pass value not using container?
Example:
FormX(IUserRepo, IOrderRepo, EnumSector)
IUserRepo and IOrderRepo will be passed through container using your method by FormOpener. But how can i pass EnumSector?
I mean i could do in container staticly :
_container.RegisterInitializer<FormUsersNew>(instance => { instance._enumSekctor= EnumSector.Fire; });
But i would prefer to say in this place dynamically somehow:
private void BtnAddUser_Click(object sender, EventArgs e)
{
var ret = this.formOpener.GetForm<FormUsersNew>();
//ret.EnumSector = EnumSector.Fire <==============
ret.ShowDialog();
}
- Is there any way to get real instance type of form?
We have:
var myform = this.formOpener.GetForm<FormUsersNew>();
ret.ShowDialog();
i mean i want myForm to be of type FormUsersNew - the real instance type (not type of Form)