New to Telerik UI for WinFormsStart a free 30-day trial

Using Custom Mention Provider

Updated over 6 months ago

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

C#

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));
        }
    }
}

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.

C#

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);
        }
    }
}

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

C#
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;
    }
}

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

C#
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);

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

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

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

C#

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());
        }
    }
}
 

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