Pengenalan Data Binding

Pola BindingSource untuk menghubungkan koleksi dengan kontrol antarmuka.

Daftar isi

Kontrol antarmuka dan koleksi data berada di dua sisi yang berbeda, yaitu tampilan yang harus diperbarui dan data yang terus berubah. Data binding (data binding) adalah mekanisme penghubung keduanya, sehingga perubahan pada satu sisi mengalir ke sisi lain tanpa kode penyalin manual. Topik ini membahas masalah yang diselesaikannya, pola BindingSource sebagai perantara, form contoh daftar catatan, serta alasan designer Visual Studio membangun pengikatannya lewat perantara yang sama.

Sinkronisasi antara kontrol dan sumber data#

Satu layar sederhana sudah menuntut penyalinan dua arah. Saat pemilihan baris pada DataGridView dipindahkan, isi TextBox judul harus mengikuti baris aktif, dan sebaliknya setiap perubahan isi TextBox harus ditulis kembali ke catatan yang sedang aktif. Tanpa mekanisme bantu, kedua arah itu ditulis sebagai prosedur event seperti berikut.

vb Contoh: penyalinan manual tanpa binding
' tidak-dijalankan
Private Sub grid_CellEnter(
        sender As Object, e As DataGridViewCellEventArgs) Handles grid.CellEnter
    kotakJudul.Text = CStr(grid.CurrentRow.Cells("Judul").Value)
End Sub

Prosedur serupa ditulis untuk arah balik, untuk setiap kontrol tambahan, dan untuk setiap layar baru. Jumlah kode penyalinnya tumbuh sebanding dengan jumlah kontrol dikalikan jumlah layar, dan satu tempat yang terlupa membuat satu tampilan menampilkan data yang sudah basi. Data binding memindahkan seluruh penyalinan itu ke infrastruktur .NET, sehingga kode aplikasi cukup menyebut pasangan kontrol dan propertinya.

Pola BindingSource sebagai perantara#

Pola yang lazim menyisipkan satu objek BindingSource di tengah, sehingga alurnya berupa koleksi, BindingSource, lalu kontrol. Diagram berikut memperlihatkan perannya.

Pola data binding dengan BindingSource sebagai perantaraList(Of Catatan)koleksi dataBindingSourceperantaraDataGridViewTextBoxDataSourceDataSourceDataBindings,dua arah
Pola data binding dengan BindingSource sebagai perantara

Koleksi dipasang pada properti DataSource milik BindingSource, dan kontrol mengikat lewat BindingSource yang sama, bukan langsung ke koleksi. BindingSource menjaga penanda baris aktif, menerbitkan properti Current, dan menyebarkan pemberitahuan perubahan ke semua kontrol yang terikat padanya. Dengan satu perantara bersama, DataGridView dan TextBox selalu menunjuk catatan yang sama, dan perubahan dari sisi mana pun sampai ke sisi satunya.

Form contoh daftar catatan#

Form berikut menerapkan pola di atas untuk tiga catatan. DataGridView membaca seluruh koleksi lewat BindingSource, sedangkan TextBox terikat pada properti Judul baris aktif. Seluruh form dibangun di dalam kode agar mudah dibaca, dan pada lingkungan tanpa layar kode hanya diperiksa kompilasinya.

vb FormBinding.vb
' tidak-dijalankan
Imports System.Drawing
Imports System.Windows.Forms

' Kelas data sederhana yang menjadi sumber koleksi
Class Catatan
    Public Property Id As Integer
    Public Property Judul As String
    Public Property Isi As String
End Class

Public Class FormBinding
    Inherits Form

    Private sumber As New BindingSource()
    Private grid As New DataGridView()
    Private labelJudul As New Label()
    Private kotakJudul As New TextBox()

    Sub New()
        Text = "Daftar Catatan"
        ClientSize = New Size(440, 320)

        Dim arsip As New List(Of Catatan) From {
            New Catatan With {.Id = 1, .Judul = "Rapat awal", .Isi = "Menyusun jadwal proyek"},
            New Catatan With {.Id = 2, .Judul = "Rapat lanjutan", .Isi = "Meninjau perkembangan"},
            New Catatan With {.Id = 3, .Judul = "Evaluasi", .Isi = "Menilai capaian awal"}
        }

        ' Koleksi dipasang pada perantara, bukan langsung pada kontrol
        sumber.DataSource = arsip

        grid.DataSource = sumber
        grid.Location = New Point(12, 12)
        grid.Size = New Size(416, 230)
        grid.ReadOnly = True
        grid.AllowUserToAddRows = False
        grid.AutoGenerateColumns = True
        grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill

        labelJudul.Text = "Judul catatan aktif:"
        labelJudul.Location = New Point(12, 252)
        labelJudul.Size = New Size(416, 20)

        ' Kontrol teks terikat pada properti Judul lewat perantara yang sama
        kotakJudul.DataBindings.Add("Text", sumber, "Judul")
        kotakJudul.Location = New Point(12, 274)
        kotakJudul.Size = New Size(416, 23)

        Controls.Add(grid)
        Controls.Add(labelJudul)
        Controls.Add(kotakJudul)
    End Sub
End Class

Pada konstruktor, sumber.DataSource = arsip memasang koleksi pada perantara, lalu grid.DataSource = sumber mengikat grid ke perantara yang sama dan bukan langsung ke arsip. Baris kotakJudul.DataBindings.Add("Text", sumber, "Judul") menambahkan pengikatan properti Text ke properti Judul item aktif. Saat program berjalan, memilih baris mengubah isi TextBox, dan mengetik di TextBox mengubah Judul catatan aktif, karena pengikatan teks berlaku dua arah secara bawaan.

Demo pola perantara di peramban#

Demo berikut meniru pola perantara dengan HTML dan JavaScript. Tabel berperan sebagai DataGridView, kotak teks sebagai kontrol terikat, dan objek perantara pada skripnya sebagai BindingSource. Klik satu baris untuk memindahkan baris aktif, lalu sunting kotak teks dan amati baris yang bersangkutan ikut berubah.

Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8">
<title>Pola perantara data binding</title>
<style>
  body { font-family: system-ui, sans-serif; margin: 12px; font-size: 14px; color: #243342; }
  #papan { display: flex; gap: 18px; align-items: flex-start; }
  table { border-collapse: collapse; }
  th, td { border: 1px solid #b9c2cc; padding: 4px 12px; text-align: left; }
  th { background: #eef2f6; }
  tbody td { cursor: pointer; }
  tr.aktif td { background: #d9e8f7; }
  #panel { min-width: 230px; }
  #panel label { display: block; margin-bottom: 4px; }
  #panel input { width: 210px; padding: 4px 6px; }
  #status { margin-top: 10px; color: #44566b; font-size: 12.5px; }
</style>
</head>
<body>
<div id="papan">
  <table id="grid" aria-label="Tiruan DataGridView">
    <thead><tr><th>Id</th><th>Judul</th></tr></thead>
    <tbody></tbody>
  </table>
  <div id="panel">
    <label for="kotakJudul">Judul catatan aktif</label>
    <input id="kotakJudul" type="text">
    <div id="status"></div>
  </div>
</div>
<script>
  // Koleksi data: padanan List(Of Catatan)
  const arsip = [
    { Id: 1, Judul: "Rapat awal" },
    { Id: 2, Judul: "Rapat lanjutan" },
    { Id: 3, Judul: "Evaluasi" }
  ];

  // Perantara: padanan BindingSource
  const perantara = {
    posisi: 0,
    itemSekarang() { return arsip[this.posisi]; }
  };

  const tbody = document.querySelector("#grid tbody");
  const kotak = document.getElementById("kotakJudul");
  const status = document.getElementById("status");

  function tampilkan() {
    tbody.innerHTML = "";
    arsip.forEach((catatan, indeks) => {
      const baris = document.createElement("tr");
      if (indeks === perantara.posisi) baris.className = "aktif";
      const selId = document.createElement("td");
      const selJudul = document.createElement("td");
      selId.textContent = catatan.Id;
      selJudul.textContent = catatan.Judul;
      baris.appendChild(selId);
      baris.appendChild(selJudul);
      baris.addEventListener("click", () => {
        // kontrol -> perantara: posisi baris aktif berpindah
        perantara.posisi = indeks;
        tampilkan();
      });
      tbody.appendChild(baris);
    });
    // koleksi -> perantara -> kontrol
    kotak.value = perantara.itemSekarang().Judul;
    status.textContent =
      "Perantara: baris " + (perantara.posisi + 1) + " dari " + arsip.length;
  }

  kotak.addEventListener("input", () => {
    // kontrol -> perantara -> koleksi
    perantara.itemSekarang().Judul = kotak.value;
    const sel = tbody.rows[perantara.posisi].lastElementChild;
    sel.textContent = kotak.value;
  });

  tampilkan();
</script>
</body>
</html>

Mengapa designer Visual Studio memakai pola ini#

Saat tabel dari jendela Data Sources diseret ke form, Visual Studio menambahkan komponen BindingSource pada form dan mengikat kontrol lewat komponen itu. Pola perantara memberi tiga keuntungan bagi designer. Pertama, dialog konfigurasi binding dapat menyebut properti perantara saat form masih dirancang, jauh sebelum data nyatanya ada. Kedua, mengganti sumber data cukup dilakukan pada satu properti DataSource, dan seluruh kontrol mengikutinya tanpa penyuntingan satu per satu. Ketiga, pelacakan baris aktif oleh BindingContext dan CurrencyManager bekerja atas perantara, sehingga banyak kontrol tetap selaras pada satu posisi.

Pola yang sama berlaku ketika form contoh pada topik ini dibangun ulang di designer. Baris sumber.DataSource = arsip dan grid.DataSource = sumber akan berpindah ke berkas FormBinding.Designer.vb, sedangkan perilaku saat program berjalan tidak berubah. Perbedaannya hanya letak penulisan, sehingga kode pada topik ini tetap menjadi peta perilakunya.

Kesalahan umum#

Kesalahan pertama adalah mengikat kontrol langsung ke List(Of T). Tampilan awal muncul, tetapi baris baru tidak muncul ketika item ditambahkan setelah binding terpasang, karena List(Of T) tidak menerbitkan pemberitahuan perubahan. Selipkan BindingSource di antaranya dan segarkan dengan ResetBindings, atau gunakan BindingList(Of T).

Kesalahan kedua adalah salah menulis nama properti pada DataBindings.Add. Nama yang tidak cocok dengan properti mana pun memunculkan ArgumentException saat form dibuat, dan pesannya menyebut nama yang tidak ditemukan. Periksa ejaan properti, termasuk huruf besar dan kecilnya.

Kesalahan ketiga adalah mengikat dua kontrol ke dua perantara berbeda yang membaca koleksi yang sama. Keduanya tetap menampilkan data, tetapi baris aktifnya berjalan sendiri-sendiri sehingga satu tampilan selalu tertinggal. Satu daftar data pada satu layar menggunakan satu BindingSource.

Ringkasan#

  • Data binding menghubungkan kontrol dan koleksi sehingga perubahan mengalir dua arah tanpa kode penyalin manual.
  • Pola yang lazim meletakkan BindingSource di antara keduanya, menjaga baris aktif, dan menyebarkan perubahan ke semua kontrol yang terikat padanya.
  • DataGridView mengikat lewat DataSource, sedangkan kontrol lain melalui DataBindings.Add dengan nama propertinya.
  • Designer Visual Studio menambahkan BindingSource dengan alasan yang sama, yaitu konfigurasi saat desain, penggantian sumber yang mudah, dan sinkronisasi baris aktif.

Referensi#