Data binding and when not to use WinForms
BindingSource, BindingList and DataGridView, plus the honest reasons to choose a different UI stack for a new project.
Binding sources and lists
WinForms binding works through a BindingSource, which acts as a cursor over an IList. Controls bind to the source, the source binds to your data, and changes flow in both directions.
public sealed class Customer : INotifyPropertyChanged
{
private string _name = string.Empty;
private bool _active;
public string Name
{
get => _name;
set { _name = value; PropertyChanged?.Invoke(this, new(nameof(Name))); }
}
public bool Active
{
get => _active;
set { _active = value; PropertyChanged?.Invoke(this, new(nameof(Active))); }
}
public event PropertyChangedEventHandler? PropertyChanged;
}
// BindingList raises ListChanged, so the grid refreshes on Add/Remove
var customers = new BindingList<Customer>(repository.Load());
var source = new BindingSource { DataSource = customers };
grid.DataSource = source;
nameBox.DataBindings.Add(nameof(TextBox.Text), source, nameof(Customer.Name),
formattingEnabled: true,
updateSourceTrigger: DataSourceUpdateMode.OnValidation);
activeCheck.DataBindings.Add(nameof(CheckBox.Checked), source, nameof(Customer.Active));
// adding to the list updates the UI automatically
customers.Add(new Customer { Name = "Ada", Active = true });| Collection | Designer/grid refresh | Use for |
|---|---|---|
List<T> | No automatic refresh on change | Static, read-only data |
BindingList<T> | Yes — raises ListChanged | Editable lists in a grid |
ObservableCollection<T> | Yes, partly — no ListChanged for the grid | Shared with WPF view models |
DataTable / DataSet | Yes, with full change tracking | Legacy code and bulk ADO.NET workflows |
IQueryable | Not supported as a live source | Materialise first with ToList() |
- Bind the grid to the
BindingSource, not to the raw list, so paging, filtering and currency stay available. INotifyPropertyChangedis what updates a bound control when code changes the object. Without it, only the grid's own edits appear.DataSourceUpdateMode.OnValidationwrites the value when focus leaves;OnPropertyChangedwrites per keystroke.BindingSource.Filterworks onDataTableand on lists that supportIBindingListView; a plain list needs a filtered view model instead.
DataGridView without surprises
grid.AutoGenerateColumns = false;
grid.AllowUserToAddRows = false;
grid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
grid.MultiSelect = false;
grid.ReadOnly = true; // use a details panel for editing instead
grid.Columns.Add(new DataGridViewTextBoxColumn
{
DataPropertyName = nameof(Customer.Name),
HeaderText = "Name",
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
});
grid.Columns.Add(new DataGridViewCheckBoxColumn
{
DataPropertyName = nameof(Customer.Active),
HeaderText = "Active",
Width = 80
});- Turn off
AutoGenerateColumnsand declare columns explicitly; column order then stops depending on property order. - For tens of thousands of rows, use virtual mode (
VirtualMode = truewithCellValueNeeded) instead of binding a giant list. - Never do I/O in
CellValueNeededorCellFormatting— those run per visible cell and per repaint.
⚠️
An exception thrown inside
CellFormatting or CellValueNeeded is reported as a generic grid error dialog and the real cause is lost. Validate inputs before the grid ever sees them.When WinForms is the wrong choice
WinForms is excellent at one thing: a dense, data-heavy internal tool on Windows, built quickly by a team that already knows it. It is a poor fit for almost everything else, and the cost of discovering that late is a rewrite.
| Requirement | Why WinForms struggles | Consider instead |
|---|---|---|
| Cross-platform desktop | Windows-only by design | MAUI, Avalonia, Uno Platform |
| Modern, animated, themed UI | Owner-drawn or third-party controls only | WPF, WinUI 3, or a web UI |
| Touch and pen input | Mouse-and-keyboard layout model | WinUI 3, MAUI |
| Testable UI logic | Logic tends to live in event handlers | WPF or a web UI with an MVVM architecture |
| Accessible, high-DPI modern UX | Requires careful manual work | WinUI 3 or WPF with proper DPI awareness |
| Deployment outside Windows | Not supported | A browser-based front end |
- Choose WinForms for internal Windows tools, legacy maintenance and utilities shipped to a controlled fleet. It is fast to build and cheap to maintain at that scope.
- Choose WPF or WinUI when you need data binding, styling, animation or a testable view-model layer.
- Choose a web UI when the users are outside your organisation, when you need mobile, or when deployment should not involve an installer.
- Whatever you choose, keep business logic in a platform-independent .NET library so a UI decision is not also a data decision.
FAQ
Why does my DataGridView not update when I change an object?
The bound type does not implement
INotifyPropertyChanged. Grid edits go through the binding and refresh the row, but a change made in code has no way to notify the grid without that event.Should a new project start with WinForms?
Only for a Windows-only internal tool where speed of delivery dominates. For anything user-facing, cross-platform or long-lived, WPF, WinUI or a web front end will cost less over the life of the product.
Related
Events and layout XAML and layout panels
Last refreshed 2026-09-18.