Development

WPF DataGrid in C#: The Ultimate Guide for Beginners

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

  1. Right-click on your project in Solution Explorer
  2. Select “Manage NuGet Packages.”
  3. 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:

  1. DataGridTextColumn: For simple text display
  2. DataGridCheckBoxColumn: For boolean values
  3. DataGridComboBoxColumn: For selection from a list
  4. DataGridHyperlinkColumn: For clickable links
  5. 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:

  1. Through the button’s DataContext property
  2. Using the DataGrid’s CurrentItem property

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

Rana Ahsan

Rana Ahsan is a seasoned software engineer and technology leader specialized in distributed systems and software architecture. With a Master’s in Software Engineering from Concordia University, his experience spans leading scalable architecture at Coursera and TopHat, contributing to open-source projects. This blog, CodeSamplez.com, showcases his passion for sharing practical insights on programming and distributed systems concepts and help educate others. Github | X | LinkedIn

View Comments

  • 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.

Recent Posts

Python Runtime Environment: Understanding Code Execution Flow

Ever wondered what happens when you run Python code? The Python runtime environment—comprising the interpreter, virtual machine, and system resources—executes your code through bytecode compilation…

2 weeks ago

Automation With Python: A Complete Guide

Tired of repetitive tasks eating up your time? Python can help you automate the boring stuff — from organizing files to scraping websites and sending…

1 month ago

Python File Handling: A Beginner’s Complete Guide

Learn python file handling from scratch! This comprehensive guide walks you through reading, writing, and managing files in Python with real-world examples, troubleshooting tips, and…

2 months ago

This website uses cookies.