Custom Control WinForms pada C#

Pada pemrograman, terdapat prinsip DRY, yaitu Don't Repeat Yourself. Salah satu penerapan konsep tersebut adalah membuat user control. Sebagai contoh user control, kita akan membuat suatu user control bernama ComboGrid yang merupakan gabungan antara ComboBox dan DataGridView.

Membuat Windows Forms Control Library dengan C#

Untuk membuat satu atau banyak custom control, sebaiknya kita membuatnya di dalam suatu project "Windows Forms Control Library", sehingga apabila kita perlu menggunakan control-control standar kita, kita tinggal menginclude project atau file dll dari project ini ke dalam solution tiap proyek kita. Buatlah project baru (new project) dengan tipe Windows Forms Control Library. Beri nama project misalnya "TrControls". Nama project ini akan menjadi nama "namespace" dari User Control yang akan kita buat.

Visual studio akan secara otomatis membuat sebuah UserControl1.cs. Hapus file tersebut dan buat ulang dengan nama ComboGrid.cs

Drag sebuah ComboBox, sebuah DataGridView dan sebuah ToolTip ke dalam kotak desain ComboGrid yang tampil dan atur properties berikut:

ComboBox:

  • Dock: Top
  • Name: Combo
  • Modifiers: Public

DataGridView:

  • Dock: Fill
  • Name: Grid
  • Modifiers: Public

ToolTip:

  • Name: Tip

Kemudian masuk ke kode program (ComboGrid.cs) dan tambahkan Properties berikut:

#region Properties
//Nama Field PK pada tabel database (Untuk pencarian berdasarkan field ini)
public string KeyField { get; set; }
//Nama Field Nama pada tabel database (Untuk pencarian berdasarkan field nama, misalnya nama barang, nama pelanggan, dll)
public string NameField { get; set; }

//Judul kolom PK pada DataGridView
private string keyHeaderText;
public string KeyHeaderText {
  get { return keyHeaderText; }
  set {
    keyHeaderText = value;
    if (value == null) return;
    if (Grid.Columns[KeyField] != null) Grid.Columns[KeyField].HeaderText = value;
  }
}

//Judul kolom Nama pada DataGridView
private string nameHeaderText;
public string NameHeaderText {
  get { return nameHeaderText; }
  set {
    nameHeaderText = value;
    if (value == null) return;
    if (Grid.Columns[NameField] != null) Grid.Columns[NameField].HeaderText = value;
  }
}

//Tulisan/tooltip yang muncul pada ComboBox
private string tipText;
public string TipText {
  get { return tipText; }
  set {
    tipText = value;
    tip.SetToolTip(Combo, tipText);
  }
}
#endregion

Isikan nilai default properties di atas pada Constructor:

public ComboGrid() {
  InitializeComponent();
  KeyField = "Key";
  NameField = "Name";
  TipText = @"Tekan F3 untuk mengganti antara kode dan nama
Tekan F6 untuk mengosongkan pilihan atau memilih semuanya";
}

Tambahkan event PilihanBerubah sehingga dapat digunakan oleh pengguna User Control kita untuk melacak terjadinya perubahan pilihan pada User Control kita:

//Event: PilihanBerubah
public delegate void PilihanBerubahHandler();
public event PilihanBerubahHandler PilihanBerubah;
protected virtual void RaisePilihanBerubah() {
  var handler = PilihanBerubah;
  if (handler != null) {
    handler();
  }
}

Berikutnya adalah tambahkan Event Handler Combo_KeyDown yaitu dengan memilih Combo pada halaman desain ComboGrid, kemudian buka panel Properties, klik tombol Events dan dobel klik event KeyDown.

Tambahkan kode berikut ke dalam event tersebut:

private void Combo_KeyDown(object sender, KeyEventArgs e) {
  //Saat menekan enter
  if (e.KeyCode == Keys.Enter) {
    //Apabila tidak ada pilihan --> Beep.
    if (Combo.SelectedItem != null) {
      //Apabila data sudah terpilih di dalam grid --> Beep.
      var barisData = (Combo.SelectedItem as DataRowView).Row;
      foreach (DataGridViewRow baris in Grid.Rows) {
        if (baris.Cells[KeyField].Value == barisData[KeyField]) {
          Console.Beep();
          return;
        }
      }
      Grid.Rows.Add(barisData.ItemArray);
      RaisePilihanBerubah();
    } else Console.Beep();
  //Saat menekan F6
  } else if (e.KeyCode == Keys.F6) {
    //Apabila Grid ada isi --> kosongkan
    if (Grid.Rows.Count > 0) {
      Grid.Rows.Clear();
      RaisePilihanBerubah();
    //Jika tidak ada isi --> Masukkan semua data
    } else {
      foreach (object a in Combo.Items) {
        var b = a as DataRowView;
        Grid.Rows.Add(b.Row.ItemArray);
      }
    }
  //Saat menekan F3
  } else if (e.KeyCode == Keys.F3) {
    //Toggle tampilan Key / Nama pada Combo
    if (Combo.DisplayMember == NameField) Combo.DisplayMember = KeyField; else Combo.DisplayMember = NameField;
  }
}

Perlu diketahui bahwa method RaisePilihanBerubah() di atas akan menjalankan event PilihanBerubah, yaitu menjalankan semua EventHandler yang terkait dengan event tersebut.

Terakhir kita menambahkan method SetDataSource yang akan digunakan untuk mengisi data ke dalam ComboBox dan DataGridView secara bersamaan.

//Method untuk mengisi DataTable ke dalam Combo dan Grid
public void SetDataSource(DataTable dt) {
  Grid.Rows.Clear();
  Grid.Columns.Clear();
  RaisePilihanBerubah();
  if (dt.Columns[KeyField] == null) throw new ApplicationException("DataTable tidak memiliki KeyField " + KeyField);
  if (dt.Columns[NameField] == null) throw new ApplicationException("DataTable tidak memiliki NameField " + NameField);
  this.Combo.DataSource = dt;
  this.Combo.DisplayMember = KeyField;
  this.Combo.AutoCompleteSource = AutoCompleteSource.ListItems;
  this.Combo.AutoCompleteMode = AutoCompleteMode.SuggestAppend;

  foreach (DataColumn kolom in dt.Columns) this.Grid.Columns.Add(kolom.ColumnName, kolom.ColumnName);
  KeyHeaderText = keyHeaderText;
  NameHeaderText = nameHeaderText;
}

Menggunakan Custom Control C#

Pada solution yang sama, tambahkan project Windows Forms Application baru (Klik kanan pada Solution -> Add -> New Project...) beri nama misalnya TestComboGrid. Kemudian pastikan bahwa project ini memiliki referensi terhadap Project Custom Control kita: TrControls.

Tambahkan ComboGrid ke dalam Form1.

Tambahkan Event Handler Form1_Load dan ComboGrid1_PilihanBerubah seperti berikut:

private void Form1_Load(object sender, EventArgs e) {
  var conn = new MySqlConnection("Host=localhost;Uid=root;Pwd=123;database=test1");
  var cmd = new MySqlCommand("", conn);
  MySqlDataReader rd;
  var adap = new MySqlDataAdapter(cmd);

  var dt = new DataTable("buku");
  cmd.CommandText = "SELECT * FROM buku";
  adap.Fill(dt);

  comboGrid1.KeyField = "kode";
  comboGrid1.NameField = "judul";
  comboGrid1.KeyHeaderText = "KODE BUKU";
  comboGrid1.NameHeaderText = "JUDUL BUKU";
  comboGrid1.SetDataSource(dt);

  comboGrid1.PilihanBerubah += comboGrid1_PilihanBerubah;
}

void comboGrid1_PilihanBerubah() {
  var terpilih = "";
  foreach (DataGridViewRow baris in comboGrid1.Grid.Rows) {
    terpilih += "- " + baris.Cells["judul"].Value.ToString() + "\r\n";
  }
  MessageBox.Show("Yang terpilih:\r\n" + terpilih);
}

Database yang dipakai di atas bernama Test1 dengan tabel bernama buku dengan field:

SHOW COLUMNS FROM buku;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| kode      | varchar(20) | NO   | PRI | NULL    |       |
| judul     | varchar(50) | YES  |     | NULL    |       |
| pengarang | varchar(50) | YES  |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
3 rows in set (0.05 sec)

Anda dapat mencoba dengan koneksi database kesukaan Anda atau apabila menggunakan MySQL seperti saya, jangan lupa menambahkan reference terhadap MySql.Data, serta tambahkan perintah

using MySql.Data.MySqlClient;

Bila menggunakan MySQL juga, Saya sudah menyediakan kode program untuk membuat database secara otomatis. Anda dapat mengganti event Form1_Load di atas menjadi seperti berikut:

private void Form1_Load(object sender, EventArgs e) {
  var conn = new MySqlConnection("Host=localhost;Uid=root;Pwd=123;database=test1");
  var cmd = new MySqlCommand("", conn);
  MySqlDataReader rd;
  var adap = new MySqlDataAdapter(cmd);

  cmd.CommandText = "SHOW DATABASES LIKE 'test1'";
  conn.Open();
  rd = cmd.ExecuteReader();
  bool adaDatabase = rd.HasRows;
  rd.Close();
  conn.Close();

  if (!adaDatabase) {
    //Buat database bila belum ada
    cmd.CommandText = "CREATE DATABASE IF NOT EXISTS test1";
    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();

    //Ubah string koneksi agar menggunakan database test1
    conn.ConnectionString = "Host=localhost;Uid=root;Pwd=123;;database=test1";

    //Buat tabel bila belum ada
    cmd.CommandText = "CREATE TABLE IF NOT EXISTS buku (kode VARCHAR(20) PRIMARY KEY, judul VARCHAR(50), pengarang VARCHAR(50)) engine=innodb";
    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();

    //Insert data percobaan
    string[][] bukus = new string[][] { 
                new string[] {"B001", "Pemrograman Visual Studio 2005", "Someone"},
                new string[] {"B002", "Pemrograman PHP dan MySQL", "The One"},
                new string[] {"B003", "Pemrograman Android", "That One"}
            };
    conn.Open();
    cmd.Transaction = conn.BeginTransaction();
    foreach (string[] buku in bukus) {
      cmd.CommandText = string.Format("INSERT INTO buku VALUES ('{0}', '{1}', '{2}')", buku);
      cmd.ExecuteNonQuery();
    }
    cmd.Transaction.Commit();
    conn.Close();
  }

  var dt = new DataTable("buku");
  cmd.CommandText = "SELECT * FROM buku";
  adap.Fill(dt);

  comboGrid1.KeyField = "kode";
  comboGrid1.NameField = "judul";
  comboGrid1.KeyHeaderText = "KODE BUKU";
  comboGrid1.NameHeaderText = "JUDUL BUKU";
  comboGrid1.SetDataSource(dt);

  comboGrid1.PilihanBerubah += comboGrid1_PilihanBerubah;
}

Source code lengkap dapat didownload di sini. Mohon maaf karena hanya tersedia versi Visual Studio 2012. Apabila menggunakan versi visual studio yang lama, silahkan coba buat ulang dengan mengcopas kode program di dalamnya atau membuka file csprojnya saja.