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

How to Display Code Snippets in Chat Messages

Environment

Product Version Product Author
2023.3.1010 RadChat for WinForms Desislava Yordanova

Description

This tutorial demonstrates a sample approach how to display C# code snippets in chat messages by using RadSyntaxEditor.

Code snippet in a Chat Message

how-to-display-code-snippet-in-chat-messages

Depending on the code snippet's language, the proper tagger has to be used to observe the respective syntax highlighting.

Since RadSyntaxEditor is a heavy control with rich functionalities, it is used as a control, and can not be used as an element. However, it is important to note that using controls in visual chat elements may slow down the scrolling and will cause visual glitches as the controls don't support clipping. Please have this in mind as side effects in case you decide to use the demo.

Solution

To achieve the above result, follow the steps:

1. Create a derivative of TextMessageItemElement and replace its ChatMessageBubbleElement with a custom one which hosts a read-only RadSyntaxEditor. Thus, you will benefit from the code formatting that RadSyntaxEditor offers.

2. Then, create a custom Chat Factory and integrate the custom message element as follows:

        public RadForm1()
        {
            InitializeComponent();

            this.radChat1.Author = new Author(Properties.Resources.bot, "Nancy");

            this.radChat1.ChatElement.ChatFactory = new CustomChatFactory();

            Author author2 = new Author(Properties.Resources.bot, "Andrew");
            ChatTextMessage message1 = new ChatTextMessage("Hello", author2, DateTime.Now.AddHours(1));
            this.radChat1.AddMessage(message1);
            ChatTextMessage message2 = new ChatTextMessage("Hi, could you please share the code snippet?", this.radChat1.Author, DateTime.Now.AddHours(1).AddMinutes(10));
            this.radChat1.AddMessage(message2);
            ChatTextMessage message3 = new ChatTextMessage("We would like to announce that in the R2 2018 release " +
                                                           "we introduced Conversational UI", author2, DateTime.Now.AddHours(3));
            this.radChat1.AddMessage(message3);
            string code1 = @"    public class ChatTextMessage : ChatMessage
    {
        private string message;

        public ChatTextMessage(string message, Author author, DateTime timeStamp)
            : this(message, author, timeStamp, null)
        { }

        public ChatTextMessage(string message, Author author, DateTime timeStamp, object userData)
            : base(author, timeStamp, userData)
        {
            this.message = message;
        }

        public string Message
        {
            get { return message; }
            set
            {
                if (this.message != value)
                {
                    this.message = value;

                    this.OnPropertyChanged(""Message"");
                }
            }
        }
    }";
            CodeSnippetChatMessage message4 = new CodeSnippetChatMessage(code1, author2, DateTime.Now.AddHours(3));
            this.radChat1.AddMessage(message4);

            ChatTextMessage message5 = new ChatTextMessage("I used another message type:", this.radChat1.Author, DateTime.Now.AddHours(3));
            this.radChat1.AddMessage(message5);

            string code2 = @"    public class MediaMessageDataItem : BaseChatDataItem
    {
        private ChatMediaMessage message;

        public MediaMessageDataItem(ChatMediaMessage message)
            : base(message)
        {
            this.message = message;
        }

        public ChatMediaMessage MediaMessage
        {
            get { return this.message; }
        }
    }";
            CodeSnippetChatMessage message6 = new CodeSnippetChatMessage(code2, this.radChat1.Author, DateTime.Now.AddHours(3));
            this.radChat1.AddMessage(message6);
        }

        public class CodeSnippetChatMessage : ChatTextMessage
        {
            public CodeSnippetChatMessage(string message, Author author, DateTime timeStamp) : base(message, author, timeStamp)
            {
            }


        }
        public class CustomChatFactory : ChatFactory
        {
            public override BaseChatDataItem CreateDataItem(ChatMessage message)
            {
                CodeSnippetChatMessage codeSnippetMessage = message as CodeSnippetChatMessage;
                if (codeSnippetMessage != null)
                {
                    return new CodeSnippetDataItem(codeSnippetMessage);
                }
                return base.CreateDataItem(message);
            }
            public override BaseChatItemElement CreateItemElement(BaseChatDataItem item)
            {
                if (item.GetType() == typeof(CodeSnippetDataItem))
                {
                    return new CodeMessageItemElement();
                }
                return base.CreateItemElement(item);
            }
        }

        public class CodeSnippetDataItem : TextMessageDataItem
        {
            public CodeSnippetDataItem(ChatTextMessage message) : base(message)
            {
            }
        }

        public class CodeMessageItemElement : TextMessageItemElement
        {
            protected override Type ThemeEffectiveType
            {
                get
                {
                    return typeof(TextMessageItemElement);
                }
            }

            public override bool IsCompatible(BaseChatDataItem data, object context)
            {
                return data.GetType() == typeof(CodeSnippetDataItem);
            }

            protected override LightVisualElement CreateMainMessageElement()
            {
                return new CustomChatMessageBubbleElement();
            }

            public override void Synchronize()
            {
                base.Synchronize();
                CustomChatMessageBubbleElement bubble = this.MainMessageElement as CustomChatMessageBubbleElement;
                bubble.DrawText = false;
                bubble.CodeElement.Document = new Telerik.WinForms.SyntaxEditor.Core.Text.TextDocument(bubble.Text);
                bubble.CodeElement.Text = bubble.Text;
            }
        }

        public class CustomChatMessageBubbleElement : ChatMessageBubbleElement
        {
            protected override Type ThemeEffectiveType
            {
                get
                {
                    return typeof(ChatMessageBubbleElement);
                }
            }

            RadHostItem host;
            RadSyntaxEditor  codeElement;

            public RadSyntaxEditor  CodeElement
            {
                get
                {
                    return this.codeElement;
                }
            }

            protected override void CreateChildElements()
            {
                 base.CreateChildElements();
                codeElement = new RadSyntaxEditor ();
                codeElement.IsWordWrapEnabled = true;
                codeElement.SyntaxEditorElement.IsReadOnly = true;
                CSharpTagger currentLanguageTagger = new CSharpTagger(codeElement.SyntaxEditorElement);
                codeElement.TaggersRegistry.RegisterTagger(currentLanguageTagger);
                host = new RadHostItem(codeElement);
                codeElement.Dock = DockStyle.Fill;
                host.MinSize = new Size(400, 200);
                this.Children.Add(host);
            }



            public override string Text
            {
                get
                {
                    return this.codeElement.Text;
                }
                set
                {
                    base.Text = value;
                    this.codeElement.Text = value;
                }
            }
        }