ABOVE;DR: Learn how to implement custom filtering, sorting, grouping, and column visibility in WPF DataGrid using MVVM patterns. Using a school grade management application as an example, this guide shows how to build a responsive, data-driven interface that helps users organize, analyze, and manage large data sets efficiently.
Modern desktop applications often require more than just displaying data. Users expect advanced capabilities such as filtering records, sorting information, grouping related data, and adjusting column visibility to quickly analyze large data sets.
Rather than building these features from scratch, you can leverage WPF DataGrid along with the MVVM pattern to create a rich and interactive data management experience.
In this guide, we’ll use a school grade management system as a practical example to demonstrate how to implement sorting, filtering, and grouping in Syncfusion.® WPF DataGrid and a clean MVVM approach.
Let’s start.
Step 1: Define the data model
Start by creating a model that represents individual student records, as shown in the following code example.
public class Grade : INotifyPropertyChanged
{
private int _id;
private string _studentName;
private string _subjectName;
private double _assignmentScore;
private double _quizScore;
private double _examScore;
private double _projectScore;
private string _comments;
public int ID
{
get
{
return _id;
}
set
{
_id = value;
OnPropertyChanged(nameof(ID));
}
}
…
…
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public double CalculateFinalGrade()
{
// Simple example calculation. Real-world grading systems often use weighted score calculations based on academic requirements.
return (AssignmentScore + QuizScore + ExamScore + ProjectScore) / 4;
}
}
Step 2: Create ViewModel
That ViewModel brings it all together by storing data, defining grid columns, and handling user interactions. In this step, we will create GradeSheetViewModel class to populate the Values collection ItemsSource binding, configuring column definitions, and implementing data manipulation logic.
public class GradeSheetViewModel : INotifyPropertyChanged
{
private ObservableCollection<Grade> grades;
public ObservableCollection<Grade> Grades
{
get
{
return grades;
}
set
{
grades = value;
OnPropertyChanged(nameof(Grades));
}
}
}
To populate a value set with default student data, see the code example below.
private void PopulateCollection()
{
Grades = new ObservableCollection<Grade>();
//Add sample data here
}
Configure DataGrid columns
Rather than automatically creating columns, explicitly defining columns gives you complete control over how the data is displayed.
private void InitializeColumns()
{
columns = new Columns();
var studentNameIdUnboundColumn = new GridUnBoundColumn
{
MappingName = "StudentID",
HeaderText = "Student ID"
};
…
…
columns.Add(gradeColumn);
var commentsColumn = new GridTextColumn
{
MappingName = "Comments",
HeaderText = "Comments"
};
columns.Add(commentsColumn);
}
You can add columns to Column collections use special objects like GridTextColumn And GridNumericColumnselected based on your data type requirements.
Each column requires two main properties:
- Mapping Name: Determines which data source properties a column is bound to.
- Header Text: Defines the column display title.
Step 3: Design the UI
Bind the XAML UI to the ViewModel and use the Column property to connect the DataGrid with the column definition, to ensure it updates dynamically.
<syncfusion:SfDataGrid ItemsSource="{Binding Grades}"
Columns="{Binding Columns}"
AutoGenerateColumnsMode="None"
AllowTriStateSorting="True"
AutoExpandGroups="True"
ColumnSizer="SizeToHeader">
<behaviors:Interaction.Behaviors>
<local:DataGridBehavior/>
</behaviors:Interaction.Behaviors>
</syncfusion:SfDataGrid>
What’s going on here?
- Source of Goods bind your student data
- Column make sure your custom column definitions are implemented
- Sorting and grouping options are activated directly
With just a few properties, the grid becomes highly interactive.
Step 4: Add data operations
An assessment system is incomplete without a method for analyzing and manipulating data. Let’s add support for filtering, sorting, grouping and column visibility.
public class GradeSheetViewModel : INotifyPropertyChanged
{
// Commands for opening a pop-up to handle columns and data manipulation.
public ICommand HideColumns { get; set; }
public ICommand HideAllColumns { get; set; }
public ICommand ShowAllColumns { get; set; }
public ICommand FilterColumns { get; set; }
public ICommand ClearFilter { get; set; }
public ICommand GroupColumns { get; set; }
public ICommand ClearGroup { get; set; }
public ICommand SortColumns { get; set; }
public ICommand ClearSort { get; set; }
private void InitializeCommands()
{
HideColumns = new RelayCommand(_=>ExecuteHideColumns());
ShowAllColumns = new RelayCommand(_=>ExecuteShowAllColumns());
HideAllColumns = new RelayCommand(_=>ExecuteHideAllColumns());
FilterColumns = new RelayCommand(_=>ExecuteFilterColumns());
ClearFilter = new RelayCommand(_=>ExecuteClearFilter());
GroupColumns = new RelayCommand(_=>ExecuteGroupColumns());
ClearGroup = new RelayCommand(_=>ExecuteClearGroups());
SortColumns = new RelayCommand(_=>ExecuteSortColumns());
ClearSort = new RelayCommand(_=>ExecuteClearSorts());
}
}
In the code example above,
- That
HideColumns,ShowAllColumnsAndHideAllColumnscommand manages column visibility in DataGrid. HideColumnsAndShowAllColumnslinked to a button or UI action, changing visibility.- That
ExecuteHideAllColumnsAndExecuteShowAllColumnsmethod iterates over a collection of columns to set the IsHidden property.
Column visibility
You can easily replace columns using the code example:
private void ExecuteHideColumns()
{
IsOpenForHideColumns = true;
// which will open the show/hide all columns popup.
}
private void ExecuteHideAllColumns()
{
foreach (var item in columns)
{
item.IsHidden = true;
}
}
private void ExecuteShowAllColumns()
{
foreach (var item in columns)
{
item.IsHidden = false;
}
}
Sorting
That SortColumns command manages DataGrid sorting behavior through related ExecuteAddSorting method, which performs two main operations.
- Removes all existing sort descriptions
- Implement new sorting based on user input.
The SortColumnDescriptions collection property will be used from the ViewModel to handle this operation, as shown in the code example below:
private void ExecuteAddSorting()
{
if (SelectedSortColumn != null)
{
SortColumnDescriptions.Clear();
var sortColumnDescription = new SortColumnDescription()
{
ColumnName = this.SelectedSortColumn.Name,
SortDirection = IsOnState
? ListSortDirection.Ascending
: ListSortDirection.Descending
};
var tempCollection = new SortColumnDescriptions();
tempCollection.Add(sortColumnDescription);
SortColumnDescriptions = tempCollection;
}
}

Grouping
That GroupColumns commands organize data into logical categories. That ExecuteAddGrouping This method removes previous grouping criteria and applies new criteria, thereby improving data analysis.
The GroupColumnDescriptions property is used here to handle this grouping operation, as shown in the code example below:
private void ExecuteAddGrouping()
{
if (SelectedGroupColumn != null)
{
GroupColumnDescriptions.Clear();
var groupColumnDescription = new GroupColumnDescription()
{
ColumnName = this.SelectedGroupColumn.Name
};
GroupColumnDescriptions.Add(groupColumnDescription);
}
}

Filtering
That FilterColumns command allows users to quickly narrow down results based on conditions.
The filtering logic uses helper methods like MakeStringFilter() And MakeNumericFilter() to evaluate user-defined filter conditions.
public bool FilterRecords(object o)
{
double res;
bool checkNumeric = double.TryParse(this.FilterText, out res);
var item = o as Grade;
if (item != null && SelectedColumn != null)
{
if (checkNumeric
&& !this.SelectedColumn.Name!.Equals("All Columns")
&& !this.SelectedCondition!.Equals("Contains"))
{
bool result = this.MakeNumericFilter(
item, this.SelectedColumn.Name,
this.SelectedCondition
);
return result;
}
else if (this.SelectedColumn.Name!.Equals("All Columns"))
{
if (item.ID!.ToString().ToLower().Contains(this.FilterText!.ToLower())
|| item.StudentName!.ToString().ToLower().Contains(this.FilterText.ToLower())
|| item.SubjectName!.ToString().ToLower().Contains(this.FilterText.ToLower())
|| item.AssignmentScore!.ToString().ToLower().Contains(this.FilterText.ToLower())
|| item.QuizScore!.ToString().ToLower().Contains(this.FilterText.ToLower())
|| item.ExamScore!.ToString().ToLower().Contains(this.FilterText.ToLower())
|| item.ProjectScore!.ToString().ToLower().Contains(this.FilterText.ToLower())
|| item.Comments!.ToString().ToLower().Contains(this.FilterText.ToLower()))
{
return true;
}
return false;
}
else
{
bool result = this.MakeStringFilter(
item,
this.SelectedColumn.Name,
this.SelectedCondition!
);
return result;
}
}
return false;
}

GitHub Reference
You can explore the full implementation of the School Gradesheet application on GitHub.
Frequently Asked Questions
How to export value sheets to Excel or PDF?
SfDataGrid provides built-in export support for Excel and PDF. You can use API like ExportToExcel() And ExportToPdf() with export options to customize headers, formatting and layout. Trigger this action from a UI button so users can download the report in their preferred format.
How to validate value values (for example, between 0–100)?
You can implement data validation in various ways: Apply IDataErrorInfo or INotifyDataErrorInfo in your model, youwith ValidationRule in the XAML binding, and add habits Validate() method before saving.
Show validation errors in the UI to prevent invalid data entry and improve user experience.
Can I add calculated columns such as GPA or letter grades?
Yes, calculated grades such as GPA or letter grades can be added easily. Extend your model logic (for example, CalculateFinalGrade()) and tie the results to the grid.
For dynamic columns, use: GridUnBoundColumn with QueryUnBoundColumnValueand value converter in ViewModel.
This approach keeps calculations clean and separate from UI logic.
How to persist value data to database or file?
Although this example uses an in-memory collection, you can extend it to persist data using Entity Framework Core (database storage), and JSON or CSV (file-based storage).
Add save/load method in ViewModel and ensuring proper error handling and UI refreshing after loading data.
How to allow users to add or edit student records in DataGrid?
Enable direct editing in DataGrid with settings AllowEditing="True"And AddNewRowPosition to insert a new line.
Bind the save action to the at command ViewModel and update ObservableCollection. Add validation to ensure required fields are filled in before saving.
Finish
By combining a structured ViewModel with a flexible WPF DataGrid, you’ve built a complete value management system that supports real-world needs such as sorting, grouping, and filtering.
This approach keeps your code clean, scalable, and easily extensible, whether you add analytics, export data, or integrate with other systems.
If you are a Syncfusion user, you can download the setup from the license and downloads page. Otherwise, you can download a free 30-day trial.
You can also contact us via the support forum, support portal, or feedback portal for questions. We are always happy to help you!
PakarPBN
A Private Blog Network (PBN) is a collection of websites that are controlled by a single individual or organization and used primarily to build backlinks to a “money site” in order to influence its ranking in search engines such as Google. The core idea behind a PBN is based on the importance of backlinks in Google’s ranking algorithm. Since Google views backlinks as signals of authority and trust, some website owners attempt to artificially create these signals through a controlled network of sites.
In a typical PBN setup, the owner acquires expired or aged domains that already have existing authority, backlinks, and history. These domains are rebuilt with new content and hosted separately, often using different IP addresses, hosting providers, themes, and ownership details to make them appear unrelated. Within the content published on these sites, links are strategically placed that point to the main website the owner wants to rank higher. By doing this, the owner attempts to pass link equity (also known as “link juice”) from the PBN sites to the target website.
The purpose of a PBN is to give the impression that the target website is naturally earning links from multiple independent sources. If done effectively, this can temporarily improve keyword rankings, increase organic visibility, and drive more traffic from search results.
Comments are closed, but trackbacks and pingbacks are open.