This my code behind form ExpressionOfNeeds
private readonly IExpressionOfNeeds _expressionOfNeeds;
public FrmExpressionOfNeeds(IExpressionOfNeeds expressionOfNeeds)
{
InitializeComponent();
_expressionOfNeeds = expressionOfNeeds;
}
private async void FrmExpressionOfNeeds_Load(object sender, EventArgs e)
{
GCData.DataSource = await _expressionOfNeeds.GetAllExpressionOfNeeds();
}
and this my code behind MainForm
private readonly IExpressionOfNeeds _expressionOfNeeds;
private readonly IService2 _service2;
private readonly IService3 _service3;
//and so on and so forth
public XtraMain()
{
InitializeComponent();
}
private void bbtnExpressionOfNeeds_ItemClick(object sender, ItemClickEventArgs e)
{
FrmExpressionOfNeeds frme = new(_expressionOfNeeds)
{
Name = "FrmExpressionOfNeeds"
};
ViewChildForm(frme);
}
private void bbtnForm2_ItemClick(object sender, ItemClickEventArgs e)
{
Form2 frme = new(_service2)
{
Name = "Form2"
};
ViewChildForm(frme);
}
private void bbtnForm3_ItemClick(object sender, ItemClickEventArgs e)
{
Form3 frme = new(_service3)
{
Name = "Form3"
};
ViewChildForm(frme);
}
and so on and so forth
and this is my code behind Program class
static void Main()
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddScoped<XtraMain>();
services.AddSingleton<ISqlDataAccess, SqlDataAccess>();
services.AddSingleton<IExpressionOfNeeds, ExpressionOfNeeds>();
});
var host = builder.Build();
using (var serviceScope = host.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var mainform = services.GetRequiredService<XtraMain>();
Application.Run(mainform);
}
}
the problem is that the value of _expressionOfNeeds is always null and I can't find a way to Initialize it
Update
I have lots of forms and lots of Interfaces
I've only limited it to one example so the code isn't too big.
CodePudding user response:
I would suggest creating a factory to get the forms needed by the main form
public interface IFormFactory {
TForm Create<TForm>() where TForm : Form;
}
assuming the types to be created in this case all derive from Form
the implementation will use the service provider to resolve provided form type
public class FormFactory: IFormFactory {
private readonly IServiceProvider services;
public FormFactory(IServiceProvider services) {
this.services = services;
}
public TForm Create<TForm>() where TForm : Form {
return services.GetRequiredService<TForm>();
}
}
The main form will need to depend on the factory so that it can create the forms as needed
//...
private readonly IFormFactory factory;
public XtraMain(IFormFactory factory) {
InitializeComponent();
this.factory = factory;
}
private void bbtnExpressionOfNeeds_ItemClick(object sender, ItemClickEventArgs e) {
FrmExpressionOfNeeds frme = factory.Create<FrmExpressionOfNeeds>();
frme.Name = "FrmExpressionOfNeeds";
ViewChildForm(frme);
}
private void bbtnForm2_ItemClick(object sender, ItemClickEventArgs e) {
Form2 frme = factory.Create<Form2>();
frme.Name = "Form2";
ViewChildForm(frme);
}
private void bbtnForm3_ItemClick(object sender, ItemClickEventArgs e) {
Form3 frme = factory.Create<Form3>();
frme.Name = "Form3";
ViewChildForm(frme);
}
//...
Make sure everything to be resolved by the service provider is registered at startup
static void Main() {
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) => {
services.AddScoped<XtraMain>();
services.AddTransient<FrmExpressionOfNeeds>();
services.AddTransient<Form2>();
services.AddTransient<Form3>();
services.AddSingleton<ISqlDataAccess, SqlDataAccess>();
services.AddSingleton<IExpressionOfNeeds, ExpressionOfNeeds>();
services.AddSingleton<IFormFactory, FormFactory>();
});
var host = builder.Build();
using (var serviceScope = host.Services.CreateScope()) {
IServiceProvider services = serviceScope.ServiceProvider;
XtraMain mainform = services.GetRequiredService<XtraMain>();
Application.Run(mainform);
}
}
That way all dependencies can be resolved and injected by the container regardless of how many forms and interfaces there are.
CodePudding user response:
You are almost there, but you have forgotten to inject the dependency to the constructor. You can find a step by step example in the following post:
Assuming you have a MainForm which has a dependency to ISomeServie, then you should have a constructor like this:
IMyService _myService;
public MainForm(IMyService myService)
{
_myService = myService;
}
Then once you register MainForm
and IMyService
into the DI container and get the instance from service provider, everything will work as expected. Here is the main entry point:
static class Program
{
public static IServiceProvider ServiceProvider { get; private set; }
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
var host = CreateHostBuilder().Build();
ServiceProvider = host.Services;
Application.Run(ServiceProvider.GetRequiredService<MainForm>());
}
static IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((context, services)=>{
services.AddTransient<IMyServiceService, MyService>();
services.AddTransient<MainForm>();
});
}
}