New to Telerik UI for WPF? Download free 30-day trial

Getting Started with WPF ExpressionEditor

This tutorial will walk your through the creation of a sample application containing RadExpressionEditor and will show you how to:

  • Use RadExpressionEditor in your project;

  • Utilize RadExpressionEditor with other controls.

Assembly References

To use the RadExpressionEditor in your projects you have to add references to the following assemblies:

  • Telerik.Windows.Controls
  • Telerik.Windows.Controls.Data
  • Telerik.Windows.Controls.Input
  • Telerik.Windows.Controls.Expressions
  • Telerik.Windows.Controls.Navigation
  • Telerik.Windows.Data
  • Telerik.Windows.Documents
  • Telerik.Windows.Documents.Core
  • Telerik.Windows.Documents.Flow

You can find the required assemblies for each control from the suite in the Controls Dependencies help article.

Adding Telerik Assemblies Using NuGet

To use RadExpressionEditor when working with NuGet packages, install the Telerik.Windows.Controls.Expressions.for.Wpf.Xaml package. The package name may vary slightly based on the Telerik dlls set - Xaml or NoXaml

Read more about NuGet installation in the Installing UI for WPF from NuGet Package article.

Adding RadExpressionEditor to the project

  • Create a new project;

If you are using .NET 6 and later, please note that instead of the Telerik.Windows.Documents.dll you need to use the new Telerik.Windows.Controls.RichTextBox.dll assembly.

In case you use Implicit Styles, please make sure all the needed resource dictionaries are merged:

  • System.Windows.xaml
  • Telerik.Windows.Controls.xaml
  • Telerik.Windows.Controls.Expressions.xaml
  • Telerik.Windows.Controls.Navigation.xaml
  • Telerik.Windows.Documents.xaml
  • Define RadExpressionEditor as demonstrated below:

Example 1

  <telerik:RadExpressionEditor x:Name="expressionEditor" /> 

Now, when running the application, RadExpressionEditor will be displayed:

WPF RadExpressionEditor Initial Layout

Binding RadExpressionEditor

The scenario we will try to create here would be to implement RadExpressionEditor as an advanced manual filter for RadGridView. For that purpose, we will firstly create a new class Employee with a couple of exposed properties and a method creating sample data:

Example 2

public class Employee  
 { 
  public string FirstName 
  { 
   get; 
   set; 
  } 
  public string LastName 
  { 
   get; 
   set; 
  } 
  public string Occupation 
  { 
   get; 
   set; 
  } 
  public DateTime StartingDate 
  { 
   get; 
   set; 
  } 
  public bool IsMarried 
  { 
   get; 
   set; 
  }   
  public int Salary 
  { 
   get; 
   set; 
  } 
  public Employee() 
  { 
  } 
  public static ObservableCollection<Employee> GetEmployees() 
  { 
   ObservableCollection<Employee> employees = new ObservableCollection<Employee>(); 
   employees.Add(new Employee() { FirstName = "Sarah", LastName = "Blake", Occupation = "Supplied Manager", StartingDate = new DateTime(2005, 04, 12), IsMarried = true, Salary = 3500 }); 
   employees.Add(new Employee() { FirstName = "Jane", LastName = "Simpson", Occupation = "Security", StartingDate = new DateTime(2008, 12, 03), IsMarried = true, Salary = 2000 }); 
   employees.Add(new Employee() { FirstName = "John", LastName = "Peterson", Occupation = "Consultant", StartingDate = new DateTime(2005, 04, 12), IsMarried = false, Salary = 2600 }); 
   employees.Add(new Employee() { FirstName = "Peter", LastName = "Bush", Occupation = "Cashier", StartingDate = new DateTime(2005, 04, 12), IsMarried = true, Salary = 2300 }); 
   return employees; 
  } 
 } 
Public Class Employee 
 Public Property FirstName() As String 
  Get 
   Return m_FirstName 
  End Get 
  Set 
   m_FirstName = Value 
  End Set 
 End Property 
 Private m_FirstName As String 
 Public Property LastName() As String 
  Get 
   Return m_LastName 
  End Get 
  Set 
   m_LastName = Value 
  End Set 
 End Property 
 Private m_LastName As String 
 Public Property Occupation() As String 
  Get 
   Return m_Occupation 
  End Get 
  Set 
   m_Occupation = Value 
  End Set 
 End Property 
 Private m_Occupation As String 
 Public Property StartingDate() As DateTime 
  Get 
   Return m_StartingDate 
  End Get 
  Set 
   m_StartingDate = Value 
  End Set 
 End Property 
 Private m_StartingDate As DateTime 
 Public Property IsMarried() As Boolean 
  Get 
   Return m_IsMarried 
  End Get 
  Set 
   m_IsMarried = Value 
  End Set 
 End Property 
 Private m_IsMarried As Boolean 
 Public Property Salary() As Integer 
  Get 
   Return m_Salary 
  End Get 
  Set 
   m_Salary = Value 
  End Set 
 End Property 
 Private m_Salary As Integer 
 Public Sub New() 
 End Sub 
 Public Shared Function GetEmployees() As ObservableCollection(Of Employee) 
  Dim employees As New ObservableCollection(Of Employee)() 
  employees.Add(New Employee() With { _ 
   Key .FirstName = "Sarah", _ 
   Key .LastName = "Blake", _ 
   Key .Occupation = "Supplied Manager", _ 
   Key .StartingDate = New DateTime(2005, 4, 12), _ 
   Key .IsMarried = True, _ 
   Key .Salary = 3500 _ 
  }) 
  employees.Add(New Employee() With { _ 
   Key .FirstName = "Jane", _ 
   Key .LastName = "Simpson", _ 
   Key .Occupation = "Security", _ 
   Key .StartingDate = New DateTime(2008, 12, 3), _ 
   Key .IsMarried = True, _ 
   Key .Salary = 2000 _ 
  }) 
  employees.Add(New Employee() With { _ 
   Key .FirstName = "John", _ 
   Key .LastName = "Peterson", _ 
   Key .Occupation = "Consultant", _ 
   Key .StartingDate = New DateTime(2005, 4, 12), _ 
   Key .IsMarried = False, _ 
   Key .Salary = 2600 _ 
  }) 
  employees.Add(New Employee() With { _ 
   Key .FirstName = "Peter", _ 
   Key .LastName = "Bush", _ 
   Key .Occupation = "Cashier", _ 
   Key .StartingDate = New DateTime(2005, 4, 12), _ 
   Key .IsMarried = True, _ 
   Key .Salary = 2300 _ 
  }) 
  Return employees 
 End Function 
End Class 

In our case we will create a simple ViewModel taking care for the connection between the model and view. It will be set as DataContext of the application.

Example 3

public class MyViewModel 
 { 
  private ObservableCollection<Employee> employees; 
  public ObservableCollection<Employee> Employees 
  { 
   get 
   { 
    if (this.employees == null) 
    { 
     this.employees = Employee.GetEmployees(); 
    } 
    return this.employees; 
   } 
  }   
 } 
Public Class MyViewModel 
 Private m_employees As ObservableCollection(Of Employee) 
 Public ReadOnly Property Employees() As ObservableCollection(Of Employee) 
  Get 
   If Me.m_employees Is Nothing Then 
    Me.m_employees = Employee.GetEmployees() 
   End If 
   Return Me.m_employees 
  End Get 
 End Property 
End Class 

Once we declared the business object and the corresponding ViewModel, we can define RadExpressionEditor and bind it appropriately.

Example 4

<Window x:Class="RadExpressionEditor_WPF.MainPage" 
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" 
             xmlns:my="clr-namespace:RadExpressionEditor_WPF" 
             mc:Ignorable="d" d:DesignHeight="700" d:DesignWidth="700"> 
 <Window.Resources> 
  <my:MyViewModel x:Key="MyViewModel" /> 
 </Window.Resources> 
 <Grid DataContext="{StaticResource MyViewModel}"> 
  <Grid.RowDefinitions> 
   <RowDefinition Height="" /> 
   <RowDefinition Height=""/> 
   <RowDefinition Height="Auto"/> 
  </Grid.RowDefinitions> 
  <telerik:RadGridView x:Name="GridView" ItemsSource="{Binding Employees}" CanUserFreezeColumns="False"             RowIndicatorVisibility="Collapsed" /> 
  <telerik:RadExpressionEditor Item="{Binding Employees[0]}" Grid.Row="1" 
                                     x:Name="ExpressionEditor"  
                                     ExpressionChanged="ExpressionEditor_ExpressionChanged"/> 
  </Grid> 
</Window> 

The functionality for defining a filter for RadGridView will be implemented in the handler of ExpressionChanged event:

Example 5

private FilterDescriptor<Employee> genericFilterDescriptor = new FilterDescriptor<Employee>(); 
private void ExpressionEditor_ExpressionChanged(object sender, Telerik.Windows.RadRoutedEventArgs e) 
  { 
   if (this.ExpressionEditor.Expression != null && this.ExpressionEditor.Expression.GetType() == typeof(Expression<Func<Employee, bool>>)) 
   { 
    this.genericFilterDescriptor.FilteringExpression = (Expression<Func<Employee, bool>>)this.ExpressionEditor.Expression; 
    if (!this.GridView.FilterDescriptors.Contains(this.genericFilterDescriptor)) 
    { 
     this.GridView.FilterDescriptors.Add(this.genericFilterDescriptor); 
    } 
   } 
   else if (this.ExpressionEditor.Expression == null) 
   { 
    if (this.GridView.FilterDescriptors.Contains(this.genericFilterDescriptor)) 
    { 
     this.GridView.FilterDescriptors.Remove(this.genericFilterDescriptor); 
    }     
   } 
  } 
    Private genericFilterDescriptor As New FilterDescriptor(Of Employee)() 
Private Sub ExpressionEditor_ExpressionChanged(sender As Object, e As Telerik.Windows.RadRoutedEventArgs) 
 If Me.ExpressionEditor.Expression IsNot Nothing AndAlso Me.ExpressionEditor.Expression.GetType = GetType(Expression(Of Func(Of Employee, Boolean))) Then 
  Me.genericFilterDescriptor.FilteringExpression = DirectCast(Me.ExpressionEditor.Expression, Expression(Of Func(Of Employee, Boolean))) 
  If Not Me.GridView.FilterDescriptors.Contains(Me.genericFilterDescriptor) Then 
   Me.GridView.FilterDescriptors.Add(Me.genericFilterDescriptor) 
  End If 
 ElseIf Me.ExpressionEditor.Expression Is Nothing Then 
  If Me.GridView.FilterDescriptors.Contains(Me.genericFilterDescriptor) Then 
   Me.GridView.FilterDescriptors.Remove(Me.genericFilterDescriptor) 
  End If 
 End If 
End Sub 

On running the application and testing the functionality of adding a filter descriptor for RadGridView, you should see a similar result:

WPF RadExpressionEditor and RadGridViewWPF RadExpressionEditor Filtering RadGridView

Still, using the Calculation Panel and the items in each Category, you are empowered to create far more complex filtering expressions.

You can access ExpressionEditor.Expression.Type.

RadExpressionEditor provides support for dynamic objects with ICustomTypeProvider or ICustomTypeDescriptor implementation. It will scan the object's properties and show them in the Fields list.

Customizing the editor

You can edit the template of the control, extend its default editor and use your custom version of it to serve your requirements. The default editor for the ExpressionEditor is an ExpressionTextBox.

Pasting

By default pasting in the editor is not supported. This is the behavior as the inner ExpressionTextBox is configured to not accept returns. You can resolve this with the following approach ensuring the pasting will be executed in code:

Example 7

void MainWindow_Loaded(object sender, RoutedEventArgs e) 
{ 
    this.expressionEditor.OnApplyTemplate(); 
 
    ExpressionTextBox expressionTextBox = ((ExpressionTextBox)this.expressionEditor.Template.FindName("PART_ExpressionNodeEditor", this.expressionEditor)); 
    RadRichTextBox radRichTextBox = ((RadRichTextBox)expressionTextBox.Template.FindName("RichTextBox", expressionTextBox)); 
 
    radRichTextBox.CommandExecuting += radRichTextBox_CommandExecuting; 
} 
 
void radRichTextBox_CommandExecuting(object sender, CommandExecutingEventArgs e) 
{ 
    RadRichTextBox radRichTextBox = (RadRichTextBox)sender; 
 
    if (e.Command is PasteCommand) 
    { 
        e.Cancel = true; 
        radRichTextBox.Insert(Clipboard.GetText()); 
    } 
}      

Setting a Theme

The controls from our suite support different themes. You can see how to apply a theme different than the default one in the Setting a Theme help article.

Changing the theme using implicit styles will affect all controls that have styles defined in the merged resource dictionaries. This is applicable only for the controls in the scope in which the resources are merged.

To change the theme, you can follow the steps below:

  • Choose between the themes and add reference to the corresponding theme assembly (ex: Telerik.Windows.Themes.Windows8.dll). You can see the different themes applied in the Theming examples from our WPF Controls Examples application.

  • Merge the ResourceDictionaries with the namespace required for the controls that you are using from the theme assembly. For the RadExpressionEditor, you will need to merge the following resources:

    • System.Windows.xaml
    • Telerik.Windows.Controls.xaml
    • Telerik.Windows.Controls.Expressions.xaml
    • Telerik.Windows.Controls.Navigation.xaml
    • Telerik.Windows.Documents.xaml

Example 8 demonstrates how to merge the ResourceDictionaries so that they are applied globally for the entire application.

Example 8: Merge the ResourceDictionaries

<Application.Resources> 
    <ResourceDictionary> 
        <ResourceDictionary.MergedDictionaries> 
            <ResourceDictionary Source="/Telerik.Windows.Themes.Windows8;component/Themes/System.Windows.xaml"/> 
            <ResourceDictionary Source="/Telerik.Windows.Themes.Windows8;component/Themes/Telerik.Windows.Controls.xaml"/> 
            <ResourceDictionary Source="/Telerik.Windows.Themes.Windows8;component/Themes/Telerik.Windows.Controls.Navigation.xaml"/> 
            <ResourceDictionary Source="/Telerik.Windows.Themes.Windows8;component/Themes/Telerik.Windows.Controls.Expressions.xaml"/>                   
            <ResourceDictionary Source="/Telerik.Windows.Themes.Windows8;component/Themes/Telerik.Windows.Documents.xaml"/> 
        </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Application.Resources> 

Alternatively, you can use the theme of the control via the StyleManager.

Figure 14 shows a RadExpressionEditor with the Windows8 theme applied.

Figure 14: RadExpressionEditor with the Windows8 theme

RadExpressionEditor with Windows8 theme

Telerik UI for WPF Learning Resources

In this article