
Today, I’m walking you through the ins and outs of using the WPF DataGrid in C# applications. While it might seem a bit trickier than the Windows Forms DataGrid at first glance, I promise it’s actually quite straightforward once you get the hang of it. I’ve spent countless hours working with this control, and I’m excited to share what I’ve learned to make your development journey smoother.
What You’ll Learn in This Guide
- Setting up a WPF DataGrid in your application
- Configuring columns and basic layout
- Binding data from various sources
- Adding custom controls like buttons
- Handling common events and operations
- Advanced customization techniques
Prerequisites
Before diving in, you should have:
- Basic knowledge of WPF application development
- Visual Studio 2019 or newer installed (though the concepts work with VS 2010+)
- Familiarity with C# programming
- Optional: Understanding of LINQ and database operations
Also, if you need a refresher on LINQ to SQL, check out our beginner-friendly LINQ tutorial first, as we’ll be using some database concepts in our examples.
Set Up WPF DataGrid For Your Project
Unlike Windows Forms, the DataGrid isn’t automatically included in older WPF projects. For modern .NET projects (using .NET Core 3.0+ or .NET 5/6/7/8), the DataGrid is included in the base framework. However, for older .NET Framework projects, you might need to add a reference.
For .NET Framework Projects
- Right-click on your project in Solution Explorer
- Select “Manage NuGet Packages.”
- Search for and install
System.Windows.Controls.DataGrid.Toolkit
Once installed, you’ll need to add the namespace reference to your XAML file:
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DataGrid.Toolkit"Code language: JavaScript (javascript)Or alternatively, you can use the Microsoft WPF Toolkit namespace:
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"Code language: JavaScript (javascript)For Modern .NET Projects
The DataGrid is included in the base frameworks, so you simply need to add:
xmlns:data="clr-namespace:System.Windows.Controls;assembly=PresentationFramework"Code language: JavaScript (javascript)Creating a Basic DataGrid Layout
Let’s start by creating a simple DataGrid. Here’s the XAML code:
<DataGrid x:Name="ConfigGrid" AutoGenerateColumns="False" Margin="10">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Id}" Header="ID" />
<DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" Width="200" />
<DataGridTextColumn Binding="{Binding Path=CreatedDate}" Header="Date Created" />
</DataGrid.Columns>
</DataGrid>Code language: HTML, XML (xml)The AutoGenerateColumns="False" property is crucial! It tells the DataGrid not to automatically create columns from your data source. This gives you complete control over which properties to display and how they should appear.
Understanding DataGrid Column Types
WPF DataGrid offers several column types to handle different data presentations:
- DataGridTextColumn: For simple text display
- DataGridCheckBoxColumn: For boolean values
- DataGridComboBoxColumn: For selection from a list
- DataGridHyperlinkColumn: For clickable links
- DataGridTemplateColumn: For custom controls and layouts
The most powerful of these is the DataGridTemplateColumn, which allows you to create custom UI elements within cells.
Adding Custom Controls to DataGrid
One of the most powerful features of the WPF DataGrid is the ability to embed custom controls. Here’s how to add a delete button to each row:
<DataGrid x:Name="ConfigGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Id}" Header="ID" Visibility="Hidden" />
<DataGridTextColumn Binding="{Binding Path=PartNumber}" Header="Part Number" />
<DataGridTextColumn Binding="{Binding Path=CreatedDate}" Header="Date Created" />
<DataGridTextColumn Binding="{Binding Path=Comments}" Header="Comments" Width="250" />
<DataGridTemplateColumn Header="Actions">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="btnDelete" Click="btnDelete_Click"
Padding="5,2" Margin="2">Delete</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>Code language: HTML, XML (xml)The magic happens in the DataGridTemplateColumn. Inside the DataTemplate tag, you can add virtually any WPF control – buttons, checkboxes, images, or even custom user controls!
Binding Data to the DataGrid
Now for the exciting part – populating your DataGrid with actual data. This is absolutely simple with WPF’s data binding capabilities. Here’s how to do it:
// Create or retrieve your data collection
List<Product> products = GetProductsFromDatabase();
// Assign it to the DataGrid's ItemsSource property
MyDataGrid.ItemsSource = products;Code language: PHP (php)That’s it! The DataGrid automatically binds to the properties of your objects that match the column bindings.
Data Sources You Can Use
WPF DataGrid works wonderfully with various data sources:
- Generic collections (
List<T>,ObservableCollection<T>) - DataTables and DataSets
- Entity Framework query results
- Custom collections that implement IEnumerable
- API responses (after deserialization)
- XML data (after parsing)
For real-time updates, I recommend using ObservableCollection<T> which notifies the UI when items are added or removed:
// Create an observable collection
ObservableCollection<Customer> customers = new ObservableCollection<Customer>();
// Add items
customers.Add(new Customer { Id = 1, Name = "John Doe" });
// Bind to DataGrid
CustomersGrid.ItemsSource = customers;
// Later, when you add new items, the UI updates automatically
customers.Add(new Customer { Id = 2, Name = "Jane Smith" });Code language: JavaScript (javascript)Handling Row Operations
Let’s look at handling operations on DataGrid rows. Here’s how to implement a delete function:
private void btnDelete_Click(object sender, RoutedEventArgs e)
{
try
{
// Get the clicked button
Button button = (Button)sender;
// Get the data context (your object)
var item = button.DataContext;
// Alternative method: Get from the DataGrid directly
// var item = MyDataGrid.CurrentItem;
// Cast to your type
Product product = (Product)item;
// Perform the delete operation
if (ProductManager.DeleteProduct(product.Id))
{
MessageBox.Show("Product deleted successfully!");
// Refresh the DataGrid
LoadDataGrid();
}
else
{
MessageBox.Show("Could not delete the product");
}
}
catch (Exception ex)
{
// Log the error
Console.WriteLine(ex.Message);
MessageBox.Show("An error occurred while deleting");
}
}Code language: PHP (php)A key point here is accessing the current item. You have two options:
- Through the button’s
DataContextproperty - Using the DataGrid’s
CurrentItemproperty
Both approaches work great, but I prefer the first method because it’s more reliable when you have multiple buttons in a row.
Styling and Customizing Your DataGrid
WPF offers incredible styling capabilities. Here’s a simple example to make alternate rows have different background colors:
<DataGrid AlternatingRowBackground="LightGray"
RowBackground="White"
GridLinesVisibility="Horizontal"
HeadersVisibility="Column">Code language: HTML, XML (xml)For more advanced styling, you can create complete style templates in your resources:
<Window.Resources>
<Style TargetType="{x:Type DataGrid}">
<Setter Property="BorderBrush" Value="#DDD" />
<Setter Property="HorizontalGridLinesBrush" Value="#EEE" />
</Style>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>Code language: HTML, XML (xml)Advanced DataGrid Features
1. Row Editing
The DataGrid supports in-place editing by default. To enable or disable this:
<DataGrid CanUserAddRows="False"
CanUserDeleteRows="False"
IsReadOnly="False">Code language: HTML, XML (xml)2. Cell Templates vs. Edit Templates
You can define different templates for viewing versus editing:
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Status}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource StatusOptions}}"
SelectedItem="{Binding Status}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>Code language: HTML, XML (xml)3. Sorting, Filtering, and Grouping
Enable built-in sorting with these properties:
<DataGrid CanUserSortColumns="True"
SortingMode="Automatic">Code language: HTML, XML (xml)For filtering and grouping, you’ll need to implement these yourself using collection views:
ICollectionView view = CollectionViewSource.GetDefaultView(MyDataGrid.ItemsSource);
view.Filter = item => ((Product)item).Price > 100; // Show only products over $100Code language: JavaScript (javascript)Common DataGrid Challenges and Solutions
1. Virtualization for Performance
When dealing with large datasets, enable UI virtualization:
<DataGrid VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Standard">Code language: HTML, XML (xml)2. Fixing Row Selection Issues
To ensure consistent row selection:
<DataGrid SelectionUnit="FullRow"
SelectionMode="Single">Code language: HTML, XML (xml)3. Persistent CheckBox Selection
A common issue is that checkboxes lose state when scrolling. Fix this by ensuring proper binding:
<DataGridCheckBoxColumn Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}" />Code language: HTML, XML (xml)Make sure your model implements INotifyPropertyChanged to maintain state:
public class ProductItem : INotifyPropertyChanged
{
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}Complete Working Example
Here’s a complete example putting everything together:
// XAML
<DataGrid x:Name="ProductsGrid"
AutoGenerateColumns="False"
CanUserAddRows="False"
SelectionMode="Single"
SelectionUnit="FullRow"
Margin="10">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Id}" Header="ID" />
<DataGridTextColumn Binding="{Binding Name}" Header="Product Name" Width="200" />
<DataGridTextColumn Binding="{Binding Price, StringFormat=C}" Header="Price" />
<DataGridCheckBoxColumn Binding="{Binding IsInStock}" Header="In Stock" />
<DataGridTemplateColumn Header="Actions">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="Edit" Margin="2" Click="EditButton_Click" />
<Button Content="Delete" Margin="2" Click="DeleteButton_Click" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
// C# Code
private void LoadProducts()
{
ObservableCollection<Product> products = new ObservableCollection<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 1299.99, IsInStock = true },
new Product { Id = 2, Name = "Monitor", Price = 349.99, IsInStock = true },
new Product { Id = 3, Name = "Keyboard", Price = 59.99, IsInStock = false }
};
ProductsGrid.ItemsSource = products;
}
private void EditButton_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var product = (Product)button.DataContext;
// Open edit dialog or navigate to edit page
MessageBox.Show($"Editing product: {product.Name}");
}
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var product = (Product)button.DataContext;
// Perform delete operation
MessageBox.Show($"Deleting product: {product.Name}");
// Remove from collection
var collection = (ObservableCollection<Product>)ProductsGrid.ItemsSource;
collection.Remove(product);
}Code language: PHP (php)Conclusion
The WPF DataGrid is an absolutely powerful control that gives you tremendous flexibility for displaying and manipulating tabular data. While it might seem complex at first, you’ll soon discover that its rich feature set and customization options make it far superior to the Windows Forms DataGrid.
I’ve covered the basics here, but the possibilities are practically endless. You can create master-detail views, implement drag-and-drop functionality, add row details sections, and much more.
If you have questions or run into specific issues, feel free to leave a comment below. Happy coding! 🚀
Additional Resources
- Join the WPF Community Forum
- Microsoft’s Official WPF DataGrid Documentation
- WPF DataGrid Samples on GitHub
Discover more from CodeSamplez.com
Subscribe to get the latest posts sent to your email.

Excellent tutorial, for Data grid binding, I was looking for this kind of simple one, no where else it available. you made my job easy. Thanks allot. Keep it up.
Hello
There is problem with datagrid which is i am getting that this datagrid is not persistant. I add checkbox column to datagrid when i am selecting some checkboxes and scrolling down the datagrid some checks
automatically get removed and some get added. What is the solution for that? Please provide me solution for that.