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

Using Custom Mention Provider

You can implement your own mention provider that enables you to visualize any object as a suggestion of the mentions drop-down list. You should perform the following steps to enable RadRichTextEditor to visualize suggestions for custom objects:

1. Define the custom object (mention item)

This object should implement INotifyPropertyChanged so it can be later used in the data template for the mention item.

Example 1: Custom mention item


public class OrganizationInfo : INotifyPropertyChanged
{
    private string name;
    private string abbreviation;

    public string Name
    {
        get
        {
            return this.name;
        }
        set
        {
            if (this.name != value)
            {
                this.name = value;
                this.OnPropertyChanged("Name");
            }
        }
    }

    public string Abbreviation
    {
        get
        {
            return this.abbreviation;
        }
        set
        {
            if (this.abbreviation != value)
            {
                this.abbreviation = value;
                this.OnPropertyChanged("Abbreviation");
            }
        }
    }

    public override string ToString()
    {
        return this.Name;
    }

    /// <summary> 
    /// Occurs when a property value changes. 
    /// </summary> 
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


Public Class OrganizationInfo
    Implements INotifyPropertyChanged

    Private _name As String
    Private _abbreviation As String

    Public Property Name As String
        Get
            Return Me._name
        End Get
        Set(ByVal value As String)

            If Me._name <> value Then
                Me._name = value
                Me.OnPropertyChanged("Name")
            End If
        End Set
    End Property

    Public Property Abbreviation As String
        Get
            Return Me._abbreviation
        End Get
        Set(ByVal value As String)

            If Me._abbreviation <> value Then
                Me._abbreviation = value
                Me.OnPropertyChanged("Abbreviation")
            End If
        End Set
    End Property

    Public Overrides Function ToString() As String
        Return Me.Name
    End Function

    Public Event PropertyChanged As PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Private Sub OnPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
End Class

2. Implement a custom mention provider

Example 2: Custom mention provider

This is done by inheriting the MentionProviderBase<T> class where T is the mention item. You should implement the InsertItem and DetermineItemVisibility methods. For more information about them, check the Customize the Insert Action and Customize the Filtering sections.


public class OrganizationMentionProvider : MentionProviderBase<OrganizationInfo>
{
    public override bool DetermineItemVisibility(OrganizationInfo item, string currentMentionText)
    {
        if (string.IsNullOrEmpty(currentMentionText))
        {
            return true;
        }
        else if (item == null || string.IsNullOrEmpty(item.Name))
        {
            return false;
        }
        else
        {
            string text = currentMentionText.ToUpperInvariant();
            return item.Name.ToUpperInvariant().Contains(text) ||
                item.Abbreviation.ToUpperInvariant().StartsWith(text);
        }
    }

    public override void InsertItem(RadDocument document, OrganizationInfo item)
    {
        if (item != null)
        {
            RadDocumentEditor editor = new RadDocumentEditor(document);
            editor.Insert(item.Name);
        }
    }
}


Public Class OrganizationMentionProvider
    Inherits MentionProviderBase(Of OrganizationInfo)

    Public Overrides Function DetermineItemVisibility(ByVal item As OrganizationInfo, ByVal currentMentionText As String) As Boolean
        If String.IsNullOrEmpty(currentMentionText) Then
            Return True
        ElseIf item Is Nothing OrElse String.IsNullOrEmpty(item.Name) Then
            Return False
        Else
            Dim text As String = currentMentionText.ToUpperInvariant()
            Return item.Name.ToUpperInvariant().Contains(text) OrElse item.Abbreviation.ToUpperInvariant().StartsWith(text)
        End If
    End Function

    Public Overrides Sub InsertItem(ByVal document As RadDocument, ByVal item As OrganizationInfo)
        If item IsNot Nothing Then
            Dim editor As RadDocumentEditor = New RadDocumentEditor(document)
            editor.Insert(item.Name)
        End If
    End Sub
End Class

3. Implement a data template for the custom mention provider

The usage of a custom object requires also a DataTemplate for it. This data template is used to instruct RadRichTextEditor how the item should be visualized in the mentions drop-down. You should set the visualType and dataType property of the DataTemplate to target the type of the mention item.

The mentions dialog internally uses a RadListControl. Hence, you can construct custom visual items if there is a specific design to be followed: Custom Visual Items in ListControl

If more than one DataTemplate have the same DataType exception of type InvalidOperationException is thrown with a message “This collection expects unique data types for every DataTemplate!”.

Example 3: DataTemplate for the custom mention item

public class OrganizationInfoVisualItem : RadListVisualItem
{
    private StackLayoutElement verticalStackLayout;
    private LightVisualElement nameElement;
    private Font nameFont = new Font("Segoe UI", 9, FontStyle.Bold);
    private LightVisualElement abbreviationElement;
    private Font abbreviationFont = new Font("Segoe UI", 9, FontStyle.Regular);

    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(RadListVisualItem);
        }
    }

    protected override void CreateChildElements()
    {
        base.CreateChildElements();

        this.verticalStackLayout = new StackLayoutElement();
        this.verticalStackLayout.Orientation = Orientation.Vertical;
        this.verticalStackLayout.StretchHorizontally = true;
        this.verticalStackLayout.StretchVertically = false;
        this.verticalStackLayout.ShouldHandleMouseInput = false;
        this.Children.Add(this.verticalStackLayout);

        this.nameElement = new LightVisualElement();
        this.nameElement.StretchVertically = false;
        this.nameElement.TextAlignment = ContentAlignment.MiddleLeft;
        this.nameElement.NotifyParentOnMouseInput = true;
        this.nameElement.TextWrap = true;
        this.nameElement.ShouldHandleMouseInput = false;
        this.verticalStackLayout.Children.Add(this.nameElement);

        this.abbreviationElement = new LightVisualElement();
        this.abbreviationElement.StretchVertically = false;
        this.abbreviationElement.TextAlignment = ContentAlignment.MiddleLeft;
        this.abbreviationElement.NotifyParentOnMouseInput = true;
        this.abbreviationElement.TextWrap = true;
        this.abbreviationElement.ShouldHandleMouseInput = false;
        this.verticalStackLayout.Children.Add(this.abbreviationElement);
    }

    protected override void SynchronizeProperties()
    {
        base.SynchronizeProperties();

        this.DrawText = false;

        OrganizationInfo infoItem = this.Data.DataBoundItem as OrganizationInfo;
        if (infoItem == null)
        {
            return;
        }

        this.nameElement.Text = infoItem.Name;
        this.nameElement.Font = this.nameFont;

        this.abbreviationElement.Text = $"({infoItem.Abbreviation})";
        this.abbreviationElement.Font = this.abbreviationFont;
    }
}


Public Class OrganizationInfoVisualItem
    Inherits RadListVisualItem

    Private verticalStackLayout As StackLayoutElement
    Private nameElement As LightVisualElement
    Private nameFont As Font = New Font("Segoe UI", 9, FontStyle.Bold)
    Private abbreviationElement As LightVisualElement
    Private abbreviationFont As Font = New Font("Segoe UI", 9, FontStyle.Regular)

    Protected Overrides ReadOnly Property ThemeEffectiveType As Type
        Get
            Return GetType(RadListVisualItem)
        End Get
    End Property

    Protected Overrides Sub CreateChildElements()
        MyBase.CreateChildElements()
        Me.verticalStackLayout = New StackLayoutElement()
        Me.verticalStackLayout.Orientation = Orientation.Vertical
        Me.verticalStackLayout.StretchHorizontally = True
        Me.verticalStackLayout.StretchVertically = False
        Me.verticalStackLayout.ShouldHandleMouseInput = False
        Me.Children.Add(Me.verticalStackLayout)
        Me.nameElement = New LightVisualElement()
        Me.nameElement.StretchVertically = False
        Me.nameElement.TextAlignment = ContentAlignment.MiddleLeft
        Me.nameElement.NotifyParentOnMouseInput = True
        Me.nameElement.TextWrap = True
        Me.nameElement.ShouldHandleMouseInput = False
        Me.verticalStackLayout.Children.Add(Me.nameElement)
        Me.abbreviationElement = New LightVisualElement()
        Me.abbreviationElement.StretchVertically = False
        Me.abbreviationElement.TextAlignment = ContentAlignment.MiddleLeft
        Me.abbreviationElement.NotifyParentOnMouseInput = True
        Me.abbreviationElement.TextWrap = True
        Me.abbreviationElement.ShouldHandleMouseInput = False
        Me.verticalStackLayout.Children.Add(Me.abbreviationElement)
    End Sub

    Protected Overrides Sub SynchronizeProperties()
        MyBase.SynchronizeProperties()
        Me.DrawText = False
        Dim infoItem As OrganizationInfo = TryCast(Me.Data.DataBoundItem, OrganizationInfo)

        If infoItem Is Nothing Then
            Return
        End If

        Me.nameElement.Text = infoItem.Name
        Me.nameElement.Font = Me.nameFont
        Me.abbreviationElement.Text = $"({infoItem.Abbreviation})"
        Me.abbreviationElement.Font = Me.abbreviationFont
    End Sub
End Class

4. Register the mention provider with its mention character and the new data template

After the prerequisites are completed, you should set the new members to the MentionContext property of RadRichTextEditor.

Add the provider and the data template to the MentionContext

OrganizationMentionProvider organizationMentionProvider = new OrganizationMentionProvider();
organizationMentionProvider.MentionCharacter = '#';

List<OrganizationInfo> organizations = new List<OrganizationInfo>()
{
    new OrganizationInfo(){ Name="United Nations Organization" , Abbreviation="UN"},
    new OrganizationInfo(){ Name="United Nations Children’s Fund" , Abbreviation="UNICEF"},
    new OrganizationInfo(){ Name="World Health Organization" , Abbreviation="WHO"},
    new OrganizationInfo(){ Name="United Nations Education Scientific & Cultural Organization" , Abbreviation="UNESCO"},
    new OrganizationInfo(){ Name="World Wide Fund for Nature" , Abbreviation="WWF"}
};

organizationMentionProvider.ItemsSource = organizations;
this.radRichTextEditor1.RichTextBoxElement.MentionContext.Providers.Add(organizationMentionProvider);

DataTemplate template = new DataTemplate(visualType: typeof(OrganizationInfoVisualItem),
                                           dataType: typeof(OrganizationInfo));
this.radRichTextEditor1.RichTextBoxElement.MentionContext.Templates.Add(template);


Dim organizationMentionProvider As OrganizationMentionProvider = New OrganizationMentionProvider()
organizationMentionProvider.MentionCharacter = "#"c
Dim organizations As List(Of OrganizationInfo) = New List(Of OrganizationInfo)() From {
    New OrganizationInfo() With {
        .Name = "United Nations Organization",
        .Abbreviation = "UN"
    },
    New OrganizationInfo() With {
        .Name = "United Nations Children’s Fund",
        .Abbreviation = "UNICEF"
    },
    New OrganizationInfo() With {
        .Name = "World Health Organization",
        .Abbreviation = "WHO"
    },
    New OrganizationInfo() With {
        .Name = "United Nations Education Scientific & Cultural Organization",
        .Abbreviation = "UNESCO"
    },
    New OrganizationInfo() With {
        .Name = "World Wide Fund for Nature",
        .Abbreviation = "WWF"
    }
}
organizationMentionProvider.ItemsSource = organizations
Me.radRichTextEditor1.RichTextBoxElement.MentionContext.Providers.Add(organizationMentionProvider)
Dim template As DataTemplate = New DataTemplate(visualType:=GetType(OrganizationInfoVisualItem), dataType:=GetType(OrganizationInfo))
Me.radRichTextEditor1.RichTextBoxElement.MentionContext.Templates.Add(template)

Custom Mentions

WinForms RadRichTextEditor Custom Mentions

Customize the Insert Action

You can implement your own logic determining what and how it is being inserted into the document when the users select an item from the suggestions. You might need to customize the insert logic of PersonMentionProvider or provide the one for your custom provider. This is achieved by creating a custom implementation of a provider and overriding the InsertItem method. In the following you can see how the insert action of a CustomPersonMentionProvider is implemented - it inserts only the name of the person instead of adding the mention character and a hyperlink with the person's email.

Custom insert action

public class CustomPersonMentionProvider : PersonMentionProvider
{
    public override void InsertItem(RadDocument document, PersonMentionItem item)
    {
        if (item != null)
        {
            RadDocumentEditor editor = new RadDocumentEditor(document);
            editor.Insert(item.Name);
        }
    }
}

Public Class CustomPersonMentionProvider
    Inherits PersonMentionProvider

    Public Overrides Sub InsertItem(ByVal document As RadDocument, ByVal item As PersonMentionItem)
        If item IsNot Nothing Then
            Dim editor As RadDocumentEditor = New RadDocumentEditor(document)
            editor.Insert(item.Name)
        End If
    End Sub
End Class

WinForms RadRichTextEditor Customize Insert Action

Customize the Filtering

After typing the mention character in the beginning of a span, the drop-down menu with suggestions shows. If the user continues to type, the list of suggestions is filtered. You can control how the items from the source collection are filtered by overriding the DetermineItemVisibility method in the concrete mention provider you are using.

The example shows how to implement filtering that matches only the items that start with the content inserted by the customer no matter of their casing.

Custom Filtering


public class MyFilterPersonMentionProvider : PersonMentionProvider
{
    public override bool DetermineItemVisibility(PersonMentionItem item, string currentMentionText)
    {
        if (string.IsNullOrEmpty(currentMentionText))
        {
            return true;
        }
        else if (item == null || string.IsNullOrEmpty(item.Name))
        {
            return false;
        }
        else
        {
            return item.Name.ToUpperInvariant().StartsWith(currentMentionText.ToUpperInvariant());
        }
    }
}



Public Class MyFilterPersonMentionProvider
    Inherits PersonMentionProvider

    Public Overrides Function DetermineItemVisibility(ByVal item As PersonMentionItem, ByVal currentMentionText As String) As Boolean
        If String.IsNullOrEmpty(currentMentionText) Then
            Return True
        ElseIf item Is Nothing OrElse String.IsNullOrEmpty(item.Name) Then
            Return False
        Else
            Return item.Name.ToUpperInvariant().StartsWith(currentMentionText.ToUpperInvariant())
        End If
    End Function
End Class

WinForms RadRichTextEditor Custom Filtering

Using Multiple Mention Providers

Through the MentionContext, you can register as many providers as you need and invoke their lists of items through the associated mention character.

WinForms RadRichTextEditor Multiple Mention Providers

In this article