SyntaxEditor in Chat UI

1 Answer 29 Views
Conversational UI, Chat SyntaxEditor
steven
Top achievements
Rank 1
steven asked on 17 Oct 2023, 07:14 PM

I am attempting to add a RadSyntaxEditorElement to Telerik Chat UI for Winforms using 2023.3.1010 Trial.

I receive a null reference exception in RadSyntaxEditorElement.cs > SyncZoomComboText line 1312. It says base.Dispatcher = null. (see attached image).

 

Is it possible to add the SyntaxEditorElement to chat?  If, not do you have any other recommendations for display code in chat?

 

Here is my test code modified from the examples found on your site.

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

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

            public override void Synchronize()
            {
                base.Synchronize();
                CustomCodeMessageBubbleElement bubble = this.MainMessageElement as CustomCodeMessageBubbleElement;
                bubble.DrawText = false;
            }
        }



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

            //RadTextBoxControlElement textBoxElement;
            RadSyntaxEditor radSyntaxEditor;
            RadSyntaxEditorElement radSyntaxEditorElement;

            public RadSyntaxEditor SyntaxEditor1
            {
                get
                {
                    return this.radSyntaxEditor;
                }
            }

            protected override void CreateChildElements()
            {
                base.CreateChildElements();
                radSyntaxEditorElement = new RadSyntaxEditorElement();
                radSyntaxEditorElement.ZoomComboBox.Enabled = false;
                //radSyntaxEditor.ContextMenuOpening += textBoxElement_ContextMenuOpening;
                this.Children.Add(radSyntaxEditorElement);
            }

            //private void textBoxElement_ContextMenuOpening(object sender, TreeBoxContextMenuOpeningEventArgs e)
            //{
            //    foreach (RadItem item in e.ContextMenu.Items)
            //    {
            //        if (item.Text.Contains("&Copy"))
            //        {
            //            item.Visibility = ElementVisibility.Visible;
            //        }
            //        else
            //        {
            //            item.Visibility = ElementVisibility.Collapsed;
            //        }
            //    }
            //}

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

1 Answer, 1 is accepted

Sort by
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 20 Oct 2023, 01:02 PM

Hi, Steven,

I have reviewed the provided code snippet and I believe that you followed the sample approach demonstrated in the KB article:

https://docs.telerik.com/devtools/winforms/knowledge-base/how-to-select-and-copy-text-in-chat-messages

Since RadSyntaxEditor is a heavy control with rich functionalities, it should be 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. Having this in mind as side effects, I have invested some time to prepare a sample code snippet for your reference which result is illustrated below:

 

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

Note that this is just a sample approach and it may not cover all possible cases. Feel free to modify and further extend it in a way which suits your custom requirements best.

Regards,
Dess | Tech Support Engineer, Principal
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
Conversational UI, Chat SyntaxEditor
Asked by
steven
Top achievements
Rank 1
Answers by
Dess | Tech Support Engineer, Principal
Telerik team
Share this question
or