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.
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);
}
}