Populating WinForms Controls at Runtime with C#


A Sample C# Implementation: Populating a WinForms ListView at Runtime Using C#

Used together, the code snippets and ready-made classes below will create a useable Windows app which demonstrates populating a WinForms ListView from a database at runtime with C#. Also introduced here is some exception handling, the using statement, an interface and some separation of concerns.


In your chosen IDE, create a new Windows Forms Application called FillControl. Drag and drop a ListView called lvData onto the MainForm and double-click the form's Load event.

Add a new class file to the project called ListViewRenderer.cs. Paste the following code into it:

using System;
using System.Data;
using System.Windows.Forms;

namespace FillControl
{
  public class ListViewRenderer
  {
    ListView listView;
    DataTable dataTable;

    public ListViewRenderer(ListView listView, DataTable dataTable)
    {
      this.listView = listView;
      this.dataTable = dataTable; 
    }
    
    public void PopulateControl()
    {
      listView.Items.Clear();
      listView.Columns.Clear();
    
      foreach(DataColumn dc in dataTable.Columns)
      {
        this.listView.Text = dc.ColumnName;
        this.listView.Columns.Add(dc.ColumnName);
      }
      
      for (int i = 0; i < dataTable.Rows.Count; i++)
      {
        DataRow row = dataTable.Rows[i];
        ListViewItem listViewItem = new ListViewItem(row[0].ToString().Trim());
        for (int c = 1; c < dataTable.Columns.Count; c++)
        {
          listViewItem.SubItems.Add (row[c].ToString());
        }
        listView.Items.Add(listViewItem);
      }
    }
  }
}

Add another class file to the project called Database.cs and copy this code into it:

using System;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;

namespace FillControl
{
  public class Database : IDatabase
  {
    string connectionString = "<yourConnectionString>";
    
    public Database()
    {
    }

    public DataTable GetData()
    {
		string sql = "<yourSELECTQuery>";
		
		using (DataTable dataTable = new DataTable()) {
        try
        {
          using (SqlConnection connection = 
                 new SqlConnection(connectionString))
          using (SqlCommand command = 
                 new SqlCommand(sql, connection)) {
            connection.Open();
            dataTable.Load(command.ExecuteReader());
            return dataTable;
          }   
        }
        catch (SqlException sx)
        {
          switch (sx.Number)
          {
            case 4060:
              MessageBox.Show("SqlException No " + 
                sx.Number.ToString() + ": " + sx.Message);
              break;
            case -1:
              MessageBox.Show("SqlExcetion No " +
                sx.Number.ToString() + ": " + sx.Message);
              break;
            default:
              return null;
          }
          return null;
        }
      }
    }
  }
}

Add an interface file to the project called IDatabase.cs. Here's the code:

using System;
using System.Data;

namespace FillControl
{
	public interface IDatabase
	{
		DataTable GetData();
	}
}

Finally, paste the following code into the form's MainFormLoad event code body:

DataTable dataTable = database.GetData();
ListViewRenderer lvR = new ListViewRenderer(lvData, dataTable);
lvR.PopulateControl();
lvData.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);

Add this class level variable to the form (above public MainForm()):

IDatabase database;

And add this object to the form's constructor (under InitializeComponent()).

this.database = new Database();

Add the System.Data namespace to the form's using directives

using System.Data;

Now run it.

If you've followed this exercise correctly you'll have created a small app which, with error checking, connects to and queries a database, fills an in-memory data cache with data from an external source, instantiates an object which manipulates the data and presents it inside a useful WinForms presentation control. It has separate components for data fetching (the Database class) and data presentation (the form) making the app modular, so its code is easier to maintain, reuse and test.

UML Class Diagram

UML Class Diagram


Additionally, this modularity is supplemented by the use of an Interface which enforces which properties (or Methods or Events) any data-fetching module must implement (think of an Interface as a contract between modules). This enhances the project's availability to plug-in components: For example, replacing the Database class with one that connects to another data source (e.g. a spreadsheet, a text file or a non-SqlClient database).


Home