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.
' tidak-dijalankan
Private Sub grid_CellEnter(
sender As Object, e As DataGridViewCellEventArgs) Handles grid.CellEnter
kotakJudul.Text = CStr(grid.CurrentRow.Cells("Judul").Value)
End SubProsedur 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.
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.
' 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 ClassPada 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#
- BindingSource Class — Microsoft Learn — Kelas perantara yang dijelaskan pada topik ini.
- BindingSource Component Overview — Microsoft Learn — Gambaran komponen perantara beserta manfaatnya.
- Control.DataBindings Property — Microsoft Learn — Koleksi pengikatan properti kontrol.
- DataGridView.DataSource Property — Microsoft Learn — Properti sumber data yang menerima BindingSource.
- Bind data to the DataGridView control — Microsoft Learn — Panduan pengikatan koleksi ke grid.
- CurrencyManager Class — Microsoft Learn — Pengelola posisi baris aktif di balik BindingSource.