客製化RichTextBox!

  • 3247
  • 0
  • C#
  • 2012-07-23

摘要:客製化RichTextBox!

Silverlight有提供一個好用的TextBox,叫做RichTextBox,這個UI可以放入HyperLink,圖片之類的,比原本的TextBox強多了,不過只能讀取,並不能輸入,但是是拿來顯示就很強大了。

 

在Google搜尋時大都是講解怎麼用xaml調教這個RichTextBox,但是如果我們想要binding的話,相關的文章也是有,只不過是在已經調教好的Paragraph放入binding的東西,我這邊是要分享自己去用code生成Paragraph!

 

首先,silverlight有個Behavior這個東西,可以把一些常用的元件封裝成可重復使用的元件,我們現在的需求時,當RichTextBox接收到要輸出的訊息時,就要生成Paragraph!

 

所以我們先創個新的類別,叫做ConvertRichTextBoxContentBehavior好了,然後讓它繼承RichTextBox的行為

public class ConvertRichTextBoxContentBehavior : Behavior< richtextbox >

再來我們要binding輸出的訊息,所以弄個可對外的屬性

  public static DependencyProperty ContentProperty
            = DependencyProperty.RegisterAttached(
                "Content", typeof(string),
                typeof(RichTextBox),
                new PropertyMetadata(null, OnContentChanged));

        public string Content
        {
            set
            {
                SetValue(ContentProperty, value);
            }
            get
            {
                return (string)GetValue(ContentProperty);
            }
        }

超連結的顏色屬性

        public static DependencyProperty LinkColorProperty
            = DependencyProperty.RegisterAttached("LinkColor", typeof(SolidColorBrush), typeof(RichTextBox), null);

        public SolidColorBrush LinkColor
        {
            set
            {
                SetValue(LinkColorProperty, value);
            }
            get
            {
                return (SolidColorBrush)GetValue(LinkColorProperty);
            }
        }

接下來,當binding屬性改變的時候,就要開始做處理了!所以要

       private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            string content = e.NewValue as string;

            ConvertRichTextBoxContentBehavior sender = d as ConvertRichTextBoxContentBehavior;

            if (!string.IsNullOrWhiteSpace(content) && d != null)
            {
                sender.ConvertContent(content);
            }
        }

轉換的方法

        void ConvertContent(string content)
        {
            try
            {
                // 辨識
                // 網址:(((http://)|(https://)+)[^(\s)]{1,})
                // Email:([a-zA-Z0-9_-]+@\w+\.[a-z]+(\.[a-z]+)?)
                // 電話:(\d{7,})
                // 圖片:(\[[^\]]*\])
                Regex httpRegex = new Regex(@"(((http://)|(https://)+)[^(\s)]{1,})|([a-zA-Z0-9_-]+@\w+\.[a-z]+(\.[a-z]+)?)|(\d{7,})|(\[[^\]]*\])");
                string target = content as string;
                Paragraph rootParagraph = new Paragraph();

                MatchCollection mc = httpRegex.Matches(target);
                if (mc.Count != 0)
                {
                    int flag = 0;
                    for (int i = 0; i < mc.Count; i++)
                    {
                        if (mc[i].Index != 0)
                        {
                            Run r = new Run();
                            r.Foreground = this.AssociatedObject.Foreground;
                            r.Text = target.Substring(flag, mc[i].Index - flag);

                            flag = flag + r.Text.Length;
                            rootParagraph.Inlines.Add(r);
                        }

                        Hyperlink hyperLink = new Hyperlink();
                        hyperLink.Foreground = this.LinkColor;
                        hyperLink.MouseOverForeground = this.LinkColor;

                        if (mc[i].Value.Contains("@"))
                        {
                            hyperLink.Click += new RoutedEventHandler(hyperLink_EmailClick);
                            Run r = new Run();
                            r.Text = mc[i].Value;
                            hyperLink.Inlines.Add(r);
                            rootParagraph.Inlines.Add(hyperLink);
                            flag = flag + mc[i].Length;
                        }
                        else if (mc[i].Value.Contains("http://") || mc[i].Value.Contains("https://"))
                        {
                            //URL
                            hyperLink.TargetName = "_blank";
                            hyperLink.NavigateUri = new Uri(mc[i].Value);
                            Run r = new Run();
                            r.Text = mc[i].Value;
                            hyperLink.Inlines.Add(r);
                            rootParagraph.Inlines.Add(hyperLink);
                            flag = flag + mc[i].Length;
                        }
                        else if (mc[i].Value.Contains("["))
                        {
                            // 表情符號
                            string strImg = mc[i].Value.Replace("[", "").Replace("]", "");
                            Image image = new Image();
                            StreamResourceInfo resourceInfo = Application.GetResourceStream(new System.Uri("Images/emotion/orz.png", UriKind.Relative));
                            BitmapImage bitmapImage = new BitmapImage();
                            bitmapImage.SetSource(resourceInfo.Stream);
                            image.Height = bitmapImage.PixelHeight;
                            image.Width = bitmapImage.PixelWidth;
                            image.Source = bitmapImage;
                            InlineUIContainer container = new InlineUIContainer();
                            container.Child = image;
                            rootParagraph.Inlines.Add(container);
                            flag += mc[i].Length;
                        }
                        else
                        {
                            hyperLink.Click += new RoutedEventHandler(hyperLink_PhoneClick);
                            Run r = new Run();
                            r.Text = mc[i].Value;
                            hyperLink.Inlines.Add(r);
                            rootParagraph.Inlines.Add(hyperLink);
                            flag = flag + mc[i].Length;
                        }
                    }
                    if (flag < target.Length - 0)
                    {
                        Run r = new Run();
                        r.Text = target.Substring(flag, target.Length - flag);
                        flag = flag + r.Text.Length;
                        rootParagraph.Inlines.Add(r);
                    }
                }
                else
                {
                    rootParagraph.Inlines.Add((new Run()).Text = target);
                }
                this.AssociatedObject.Blocks.Clear();
                this.AssociatedObject.Blocks.Add(rootParagraph);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Exception in Custom.RichTextBox.OnContentChanged:" + e.Message);
            }
        }

        private void hyperLink_EmailClick(object sender, RoutedEventArgs e)
        {
            EmailComposeTask ect = new EmailComposeTask();
            Hyperlink h = sender as Hyperlink;
            ect.To = (h.Inlines[0] as Run).Text;
            ect.Show();
        }

        private void hyperLink_PhoneClick(object sender, RoutedEventArgs e)
        {
            PhoneCallTask pct = new PhoneCallTask();
            Hyperlink h = sender as Hyperlink;
            pct.PhoneNumber = (h.Inlines[0] as Run).Text;
            pct.Show();
        }

裡面的有辨識Email,Http,電話號碼,還有[123]這類的資訊,所以也可以秀出圖片!

要怎麼使用呢?

<RichTextBox>
  <interactivity:Interaction.Behaviors>
    <localHelpers:ConvertRichTextBoxContentBehavior Content="{Binding Path=MsgBody}" LinkColor="White">
    </localHelpers:ConvertRichTextBoxContentBehavior>
  </interactivity:Interaction.Behaviors>
</RichTextBox>

記得要引入參考System.Windows.Interactivity