AI-Driven Natural Language Filtering in WPF DataGrid for Smarter Data Processing


TL;DR: Revolutionize WPF DataGrid filtering with AI-powered natural language processing using Azure OpenAI and Semantic Kernel. Simply type queries like “show orders above $500,” and AI translates them into precise filters. This guide walks you through setting up AI integration, implementing filter predicates, and applying them dynamically. Make data filtering effortless and intuitive!
The Syncfusion WPF DataGrid is used to display and manipulate tabular data. Its rich feature set includes functionalities like data binding, editing, sorting, filtering, and grouping. It has also been optimized to work with millions of records and handle high-frequency, real-time updates.
In this blog, we’ll see how to create FilterPredicates using AI in the WPF DataGrid.
Overview
Data filtering in apps often requires learning the complex syntax or multiple filtering options, even for non-technical users. For instance, if the user types “show all items with stock above 100” or “list customers from California with orders over $500.” Traditional DataGrid filtering can’t handle these natural language queries, making this process complex and unintuitive.
With the power of AI, we can create a much more user-friendly solution known as natural language filtering.
In this blog, we’ll walk you through building a solution using Azure OpenAI and the Semantic Kernel that allows users to type natural language queries directly into the WPF DataGrid, transforming them into actionable filters automatically.
Prerequisites
Create your own Azure Open AI Key.
Install the Microsoft.SemanticKernal and Newtonsoft.Json NuGet packages in your app.
Create a simple WPF DataGrid app
First, create a simple WPF DataGrid app using this documentation.
Implementing AI-driven natural language filtering in WPF DataGrid
Follow these steps to implement AI-driven natural language filtering in the WPF DataGrid using Azure OpenAI and Semantic Kernel:
Step 1: Install the required packages
As said before, install the Microsoft.** SemanticKernal and Newtonsoft.Json** NuGet packages. This is the open-source development kit for integrating our AI model into our app. Refer to the documentation for more details.
In the following example, we’ve installed some additional Syncfusion packages for further customization.
Step 2: Create the SemanticKernalAI class
The SemanticKernelAI class uses OpenAI’s GPT model to provide natural language responses and filtering suggestions.
The core functionality of this class is provided by the GetResponseFromGPT method, which connects to OpenAI’s GPT model and retrieves AI responses. Here, we’ll create the Kernel Builder and configure it with the following OpenAI parameters:
Model name: Specifies the OpenAI model to use.
Endpoint: The endpoint for accessing the OpenAI API.
Key: The authentication key for secure access.
Once configured, the builder initializes the kernel, providing an instance of the IChatCompletionService interface.
The GetResponseFromGPT method accepts a prompt parameter containing the user query to be processed by the AI. The AI then returns the response based on the prompt. This response will later be displayed or used to filter the DataGrid based on natural language criteria.
Refer to the following code example for creating the SemanticKernelAI class.
C#
public class SemanticKernelAI
{
/// <summary>
/// Holds the IChatCompletionService instance.
/// </summary>
private IChatCompletionService chatCompletionService;
/// <summary>
/// Holds the Kernel instance.
/// </summary>
private Kernel kernel;
/// <summary>
/// Method to get the response from OpenAI using the semantic kernel
/// </summary>
/// <param name="prompt">Prompt for the system message</param>
/// <returns>The AI results.</returns>
public async Task<string> GetResponseFromGPT(string prompt)
{
try
{
var builder = Kernel.CreateBuilder().AddAzureOpenAIChatCompletion("Your AI-Model-Name", "Your EndPoint", "Your Key");
kernel = builder.Build();
chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();
history.AddSystemMessage(prompt);
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new OpenAIPromptExecutionSettings();
openAIPromptExecutionSettings.ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions;
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
return result.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
// Return an empty string if an exception occurs
return string.Empty;
}
}
}
Step 3: Create the filter predicate class
Let’s create the AIFilterPredicate class to encapsulate the filter details, such as the column name and filtering criteria. Refer to the following code example.
C#
/// <summary>
/// Represents a filter predicate applied to a specific column in a data set.
/// </summary>
public class AIFilterPredicate
{
public string ColumnName {get; set;}
public FilterPredicate FilterPredicate {get; set;}
}
Step 4: Create a behavior class to manage the WPF DataGrid filtering with AI
The AIFilterPredicatesBehavior class is responsible for setting up and managing the AI-driven filtering on the WPF DataGrid using user-provided queries. Let’s go through each section to understand how it works.
Refer to the following class-level members of the AIFilterPredicatesBehavior class.
SemanticKernelAIService: Holds an instance of the SemanticKernelAI class to process natural language queries using AI.
dataGrid: References the WPF DataGrid control that will display filtered data.
BusyIndicator: Displays a loading indicator while the AI is processing the query.
queryTextBox: Captures user input for filtering.
result and schema: Stores the response from AI and the JSON schema, respectively, to generate filter predicates.
When the behavior class attaches to the MainWindow, it initializes the semanticKernelAIService and **schema. ** Refer to the following code example.
C#
/// <summary>
/// Called when attached.
/// </summary>
protected override void OnAttached()
{
semanticKernelAIService = new SemanticKernelAI();
schema = GetSerializedFilterPredicate();
}
Then, the schema prepares the JSON schema for filter predicates to provide context to the AI. The following is the schema for WPF DataGrid’s FilterPredicate in JSON format.
C#
/// <summary>
/// Serializes the object into a JSON string.
/// </summary>
private string GetSerializedFilterPredicate()
{
return @"
{
""definitions"": {
""FilterPredicate"": {
""type"": [""object"", ""null""],
""properties"": {
""FilterType"": {
""type"": ""string"",
""enum"": [
""LessThan"",
""LessThanOrEqual"",
""Equals"",
""NotEquals"",
""GreaterThanOrEqual"",
""GreaterThan"",
""StartsWith"",
""NotStartsWith"",
""EndsWith"",
""NotEndsWith"",
""Contains"",
""NotContains""
]
},
""FilterValue"": {},
""PredicateType"": {
""type"": ""string"",
""enum"": [""And"", ""Or"", ""AndAlso"", ""OrElse""]
},
""FilterBehavior"": {
""type"": ""string"",
""enum"": [""StronglyTyped"", ""StringTyped""]
},
""IsCaseSensitive"": {""type"": ""boolean""},
""FilterMode"": {
""type"": ""string"",
""enum"": [""Value"", ""DisplayText""]
}
},
""required"": [
""FilterType"",
""FilterValue"",
""PredicateType"",
""FilterBehavior"",
""IsCaseSensitive"",
""FilterMode""
]
}
},
""type"": ""object"",
""properties"": {
""ColumnName"": {""type"": [""string"", ""null""]},
""FilterPredicate"": {""$ref"": ""#/definitions/FilterPredicate""}
},
""required"": [""ColumnName"", ""FilterPredicate""]
}";
}
Now, execute the Prompt button. The Enter key triggers the ApplyFiltersBasedOnAIQuery whenever a user submits a query. This method handles the core filtering process, integrating the AI-generated filter predicates with DataGrid.
This method processes the query in the following steps:
- Validating query and formatting prompt: It will check whether the query is empty and get the serialized data structure of DataGrid in JSON format. The GridReportJson represents the DataGrid structure for AI. Formatting the prompt for OpenAI with clear instructions using the ValidateAndGeneratePrompt method. This method uses the user query, schema, and data structure to prepare the AI prompt. Refer to the following code examples.
private static string ValidateAndGeneratePrompt(string filterPredicate, string text, string model)
{
if (string.IsNullOrEmpty(text))
{
return null;
}
return $"Generate the JSON of type AIFilterPredicate to filter the model\n" +
$"Model: {model} for the given query\n" +
$"Query: {text} and the AIFilterPredicate schema is AIFilterPredicate : {filterPredicate}. " +
$"Do not provide any additional information except the AIFilterPredicate as JSON object. " +
$"If more than one AIFilterPredicate then separate AIFilterPredicates using a semicolon. " +
$"Rules for providing the responses: Should not include any unwanted brackets or special characters. " +
$"Filter predicates should be separated by using a semicolon.";
}
public async void ApplyFiltersBasedOnAIQuery()
{
if (!string.IsNullOrEmpty(queryTextBox.Text))
{
var gridReportJson = GetSerializedGridReport(new EmployeeInfo());
string userInput = ValidateAndGeneratePrompt(schema, queryTextBox.Text, gridReportJson);
public async void ApplyFiltersBasedOnAIQuery()
{
if (!string.IsNullOrEmpty(queryTextBox.Text))
{
var gridReportJson = GetSerializedGridReport(new EmployeeInfo());
string userInput = ValidateAndGeneratePrompt(schema, queryTextBox.Text, gridReportJson);
2.AI processing: Sends the prompt to OpenAI and receives the filter predicates.
busyIndicator.Visibility = Visibility.Visible;
busyIndicator.IsBusy = true;
result = await semanticKernelAIService.GetResponseFromGPT(userInput);
3.Process response: Cleans and splits the response into individual filter predicates.
rresult = result.Replace("json", "")
.Replace("```", "")
.Replace("\n", "");
string[] datas = result.Split(new char[] {';'});
List filterPredicates = new List();
4.Deserializing predicates: Converts the JSON response into AIFilterPredicate objects.
foreach (var data in datas)
{
if (!string.IsNullOrEmpty(data))
{
filterPredicates.Add(GetDeserializedFilterPredicate(data));
}
}
5.Applying filters: This function matches predicates to DataGrid columns and applies them. If no match is found, an error is shown. Refer to the following code example.
for (int i = 0; i < filterPredicates.Count; i++)
{
if (filterPredicates[i].ColumnName != null &&
this.dataGrid.Columns.Any(x => x.MappingName == filterPredicates[i].ColumnName) &&
filterPredicates[i].FilterPredicate != null)
{
dataGrid.Columns[filterPredicates[i].ColumnName]
.FilterPredicates
.Add(filterPredicates[i].FilterPredicate);
}
else
{
MessageBox.Show("Invalid ColumnName / FilterPredicates. Kindly provide a proper query.");
return;
}
}
6.Serialization and deserialization: Serialization and deserialization methods handle JSON serialization and deserialization, converting filter conditions into AI-compatible JSON and vice versa. Refer to the following code examples.
private string GetSerializedGridReport(EmployeeInfo report)
{
return JsonConvert.SerializeObject(report);
}
private AIFilterPredicate GetDeserializedFilterPredicate(string report)
{
return JsonConvert.DeserializeObject<AIFilterPredicate>(report);
}
/// <summary>
/// Applies filters to the data grid based on a query processed by an AI service.
/// </summary>
public async void ApplyFiltersBasedOnAIQuery()
{
if (!string.IsNullOrEmpty(queryTextBox.Text))
{
var gridReportJson = GetSerializedGridReport(new EmployeeInfo());
string userInput = ValidateAndGeneratePrompt(schema, queryTextBox.Text, gridReportJson);
if (userInput != null)
{
busyIndicator.Visibility = Visibility.Visible;
busyIndicator.IsBusy = true;
result = await semanticKernelAIService.GetResponseFromGPT(userInput);
if (!string.IsNullOrEmpty(result))
{
try
{
result = result.Replace("json", "")
.Replace("```", "")
.Replace("\n", "");
string[] datas = result.Split(';');
var filterPredicates = new List<AIFilterPredicate>();
foreach (var data in datas)
{
if (!string.IsNullOrEmpty(data))
{
filterPredicates.Add(GetDeserializedFilterPredicate(data));
}
}
foreach (var predicate in filterPredicates)
{
if (predicate.ColumnName != null &&
dataGrid.Columns.Any(x => x.MappingName == predicate.ColumnName) &&
predicate.FilterPredicate != null)
{
dataGrid.Columns[predicate.ColumnName]
.FilterPredicates
.Add(predicate.FilterPredicate);
}
else
{
MessageBox.Show("Invalid ColumnName / FilterPredicates. Kindly provide a proper query.");
return;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
busyIndicator.IsBusy = false;
busyIndicator.Visibility = Visibility.Hidden;
}
}
else
{
busyIndicator.IsBusy = false;
busyIndicator.Visibility = Visibility.Hidden;
}
}
}
}
Refer to the following output GIF image.
Implementing AI-driven natural language filtering in WPF DataGrid
GitHub reference
For more details, refer to the AI-driven natural language filtering in the WPF DataGrid GitHub demo.
Conclusion
Thanks for reading! In this blog, we’ve explored how an AI-driven approach transforms WPF DataGrid filtering, making data interaction straightforward and accessible through natural language. By bridging technical filters with user-friendly AI, it empowers users to explore and analyze data effortlessly.
Our WPF suite examples are available in the Microsoft Store. After trying it out, please share your thoughts in the comment below.
Our customers can access the latest version of Essential Studio for WPF from the License and Downloads page. If you are not a Syncfusion customer, you can download our free evaluation to explore all our controls.
You can also contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!
Related Blogs
Easily Export WPF DataGrid to PDF
Creating a Dynamic WPF Chart Dashboard to Showcase 2024 Women’s T20 World Cup Statistics
Semantic Searching using Embedding in WPF DataGrid
Create a WPF Multi-Bar Chart to Visualize U.S. vs. China Superpower Status
Subscribe to my newsletter
Read articles from syncfusion directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

syncfusion
syncfusion
Syncfusion provides third-party UI components for React, Vue, Angular, JavaScript, Blazor, .NET MAUI, ASP.NET MVC, Core, WinForms, WPF, UWP and Xamarin.