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 });
CollectionDesigner/grid refreshUse for
List<T>No automatic refresh on changeStatic, read-only data
BindingList<T>Yes — raises ListChangedEditable lists in a grid
ObservableCollection<T>Yes, partly — no ListChanged for the gridShared with WPF view models
DataTable / DataSetYes, with full change trackingLegacy code and bulk ADO.NET workflows
IQueryableNot supported as a live sourceMaterialise first with ToList()
  • Bind the grid to the BindingSource, not to the raw list, so paging, filtering and currency stay available.
  • INotifyPropertyChanged is what updates a bound control when code changes the object. Without it, only the grid's own edits appear.
  • DataSourceUpdateMode.OnValidation writes the value when focus leaves; OnPropertyChanged writes per keystroke.
  • BindingSource.Filter works on DataTable and on lists that support IBindingListView; 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 AutoGenerateColumns and declare columns explicitly; column order then stops depending on property order.
  • For tens of thousands of rows, use virtual mode (VirtualMode = true with CellValueNeeded) instead of binding a giant list.
  • Never do I/O in CellValueNeeded or CellFormatting — 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.

RequirementWhy WinForms strugglesConsider instead
Cross-platform desktopWindows-only by designMAUI, Avalonia, Uno Platform
Modern, animated, themed UIOwner-drawn or third-party controls onlyWPF, WinUI 3, or a web UI
Touch and pen inputMouse-and-keyboard layout modelWinUI 3, MAUI
Testable UI logicLogic tends to live in event handlersWPF or a web UI with an MVVM architecture
Accessible, high-DPI modern UXRequires careful manual workWinUI 3 or WPF with proper DPI awareness
Deployment outside WindowsNot supportedA 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.

Events and layout XAML and layout panels

Last refreshed 2026-09-18.