Home > database >  Dependency Injected Class Returns Null (c#,Winforms App)
Dependency Injected Class Returns Null (c#,Winforms App)

Time:07-05

I am not sure what the problem is here, so I am reaching out. I have an interfaced DataLayer class which recalls some customer data I am using to fill a gridview. I dependency inject this directly into a winform partial class (I am skipping the BusinessLayer for now). I am newer to Winforms so maybe there is something I am not seeing here or maybe I am being dense in my code.

Interface:

namespace DL
{
    public interface IRepo<T>
    {
        List<T> GetAll();
    }
}

DataLayer

namespace DL
{
    public class CustomersRepo : IRepo<Customers>
    {
        string constring = ConfigurationManager.ConnectionStrings["ConString"].ConnectionString;
        
        public List<Customers> GetAll()
        {
            List<Customers> customers = new List<Customers>();
            string sqlQuery =@"SELECT * FROM CUSTOMERS";

            using (SqlConnection con = new SqlConnection(constring))
            {
                con.Open();
                SqlCommand command = new SqlCommand(sqlQuery, con);
                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    Customers customer = new Customers();
                    customer.CustomerID = reader.GetInt32(0);
                    customer.LastName = reader.GetString(1);
                    customer.FirstName = reader.GetString(2);
                    customer.Address = reader.GetString(3);
                    customer.City = reader.GetString(4);
                    customers.Add(customer);
                }
            }
            return customers;
        }
    }
}

Dependency Injection:

    public partial class Main : Form
    {
        public List<Customers> CustomersData { get; set; }

        private IRepo<Customers> _repo;
        public Main(IRepo<Customers> repo)
        {
            _repo = repo;
        }

Main:

        public Main()
        {
            CustomersData = _repo.GetAll();
            InitializeComponent();
        }

Form Load:

        private void Main_Load(object sender, EventArgs e)
        {
            dataGridViewCust.DataSource = CustomersData;
        }

If I insert this Datalayer method directly into the form class, everything works fine. I am trying to keep to some of the design principles I learned in a recent bootcamp, and hence was trying to separate the concerns visa via dependency injection. Am I being stupid somewhere? I've looked at other examples of the similar null question on here but have not found where my problem is... Any help or advice would be appreciated. I feel like I have majorly overlooked something.

EDIT: (I've tried directly inserting the repo class as well without the IRepo abstraction.)

CodePudding user response:

You should do dependency injection in program.cs. For this, install the autofac package and write the sample codes below.

using Autofac;
using System;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1(Container.Resolve< IRepo>()));
        }

        static IContainer Configure()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<CustomersRepo>().As<IRepo>();
            builder.RegisterType<Form1>();
            return builder.Build();
        }
    }
 }

CodePudding user response:

There are several good answers on SO (e.g. datagridview

Since the DataGridView needs to respond to subsequent queries, it needs a DataSource that will notify it of changes to the customers list as they occur. In this example, I have changed List<Customer> to BindingList<Customer> and initialized it in the override for the Load event of the Main form.

/// <summary>
/// A binding list will notify DGV when data changes
/// </summary>
public BindingList<Customer> Customers { get; } = new BindingList<Customer>();
protected override void onl oad(EventArgs e)
{
    base.OnLoad(e);
    dataGridViewCust.DataSource = Customers;

    // Here we're calling a method that simulates the
    // sql query by returning a fake list of customers
    foreach (var customer in _repo.GetAllMock())
    {
        Customers.Add(customer);
    }
    foreach (DataGridViewColumn column in dataGridViewCust.Columns)
    {
        column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
    }
}

Working with BindingList

You probably noticed that the BindingList was declared as a read-only property. When a new query is performed, simply perform a Clear on it before adding the new records.

private void changeTheBindingListExample()
{
    Customers.Clear();

    foreach (
        var customer in 
        _repo.NewQueryMock("SELECT * FROM CUSTOMERS WHERE FirstName='Other'"))
    {
        Customers.Add(customer);
    }
}

enter image description here

  • Related