How to bind a TextBlock to a resource containing formatted text?

前端 未结 7 936
被撕碎了的回忆
被撕碎了的回忆 2020-11-28 08:57

I have a TextBlock in my WPF window.

 
     Some formatted text.
 

When it is r

7条回答
  •  感情败类
    2020-11-28 09:28

    I ended up needing to do this in my application and had to support many of the markup possible normally in TextBlock inlines, so I took Wallstreet Programmer's answer above (which works beautifully and is much less complicated than most other answers I found on this topic) and expanded on it. I figure someone else might find this useful.

    I haven't thoroughly tested this with ALL the tags yet, but every one I've tested has worked like a charm. I also suspect it's not the fastest code in the world, but my own testing with several thousand formatted messages in a ListView seemed surprisingly zippy. YMMV. Code is below:

    XAML:

    
    
        
    
    
    

    C#

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Media;
    
    namespace FormatTest
    {
    
    public static class FormattedTextBehavior
    {
        public class TextPart
        {
            public String mType = String.Empty;
            public Inline mInline = null;
            public InlineCollection mChildren = null;
    
            public TextPart() {}
            public TextPart(String t, Inline inline, InlineCollection col)
            {
                mType = t;
                mInline = inline;
                mChildren = col;
            }
        }
    
        private static Regex mRegex = new Regex(@"<(?/?[^>]*)>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        private static Regex mSpanRegex = new Regex("(?[^\\s=]+)=\"(?[^\\s\"]*)\"", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    
        public static string GetFormattedText(DependencyObject obj)
        {
            return (string)obj.GetValue(FormattedTextProperty);
        }
    
        public static void SetFormattedText(DependencyObject obj, string value)
        {
            obj.SetValue(FormattedTextProperty, value);
        }
    
        public static readonly DependencyProperty FormattedTextProperty =
            DependencyProperty.RegisterAttached("FormattedText",
                                                typeof(string),
                                                typeof(FormattedTextBehavior),
                                                new UIPropertyMetadata("", FormattedTextChanged));
    
        private static void FormattedTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            TextBlock textBlock = sender as TextBlock;
            FormatText(e.NewValue as string, new TextPart("TextBlock", null, textBlock.Inlines));
        }
    
        public static void FormatText(String s, TextPart root)
        {
            int len = s.Length;
            int lastIdx = 0;
            List parts = new List();
            parts.Add(root);
            Match m = mRegex.Match(s);
            while (m.Success)
            {
                String tag = m.Result("${Span}");
                if (tag.StartsWith("/"))
                {
                    String prevStr = s.Substring(lastIdx, m.Index - lastIdx);
                    TextPart part = parts.Last();
                    if (!String.IsNullOrEmpty(prevStr))
                    {
                        if (part.mChildren != null)
                        {
                            part.mChildren.Add(new Run(prevStr));
                        }
                        else if (part.mInline is Run)
                        {
                            (part.mInline as Run).Text = prevStr;
                        }
                    }
                    if (!tag.Substring(1).Equals(part.mType, StringComparison.InvariantCultureIgnoreCase))
                    {
                        Logger.LogD("Mismatched End Tag '" + tag.Substring(1) + "' (expected ) at position " + m.Index.ToString() + " in String '" + s + "'");
                    }
                    if (parts.Count > 1)
                    {
                        parts.RemoveAt(parts.Count - 1);
                        TextPart parentPart = parts.Last();
                        if (parentPart.mChildren != null)
                        {
                            parentPart.mChildren.Add(part.mInline);
                        }
                    }
                }
                else
                {
                    TextPart prevPart = parts.Last();
                    String prevStr = s.Substring(lastIdx, m.Index - lastIdx);
                    if (!String.IsNullOrEmpty(prevStr))
                    {
                        if (prevPart.mChildren != null)
                        {
                            prevPart.mChildren.Add(new Run(prevStr));
                        }
                        else if (prevPart.mInline is Run)
                        {
                            (prevPart.mInline as Run).Text = prevStr;
                        }
                    }
    
                    bool hasAttributes = false;
                    TextPart part = new TextPart();
                    if (tag.StartsWith("bold", StringComparison.InvariantCultureIgnoreCase))
                    {
                        part.mType = "BOLD";
                        part.mInline = new Bold();
                        part.mChildren = (part.mInline as Bold).Inlines;
                    }
                    else if (tag.StartsWith("underline", StringComparison.InvariantCultureIgnoreCase))
                    {
                        part.mType = "UNDERLINE";
                        part.mInline = new Underline();
                        part.mChildren = (part.mInline as Underline).Inlines;
                    }
                    else if (tag.StartsWith("italic", StringComparison.InvariantCultureIgnoreCase))
                    {
                        part.mType = "ITALIC";
                        part.mInline = new Italic();
                        part.mChildren = (part.mInline as Italic).Inlines;
                    }
                    else if (tag.StartsWith("linebreak", StringComparison.InvariantCultureIgnoreCase))
                    {
                        part.mType = "LINEBREAK";
                        part.mInline = new LineBreak();
                    }
                    else if (tag.StartsWith("span", StringComparison.InvariantCultureIgnoreCase))
                    {
                        hasAttributes = true;
                        part.mType = "SPAN";
                        part.mInline = new Span();
                        part.mChildren = (part.mInline as Span).Inlines;
                    }
                    else if (tag.StartsWith("run", StringComparison.InvariantCultureIgnoreCase))
                    {
                        hasAttributes = true;
                        part.mType = "RUN";
                        part.mInline = new Run();
                    }
                    else if (tag.StartsWith("hyperlink", StringComparison.InvariantCultureIgnoreCase))
                    {
                        hasAttributes = true;
                        part.mType = "HYPERLINK";
                        part.mInline = new Hyperlink();
                        part.mChildren = (part.mInline as Hyperlink).Inlines;
                    }
    
                    if (hasAttributes && part.mInline != null)
                    {
                        Match m2 = mSpanRegex.Match(tag);
                        while (m2.Success)
                        {
                            String key = m2.Result("${Key}");
                            String val = m2.Result("${Val}");
                            if (key.Equals("FontWeight", StringComparison.InvariantCultureIgnoreCase))
                            {
                                FontWeight fw = FontWeights.Normal;
                                try
                                {
                                    fw = (FontWeight)new FontWeightConverter().ConvertFromString(val);
                                }
                                catch (Exception)
                                {
                                    fw = FontWeights.Normal;
                                }
                                part.mInline.FontWeight = fw;
                            }
                            else if (key.Equals("FontSize", StringComparison.InvariantCultureIgnoreCase))
                            {
                                double fs = part.mInline.FontSize;
                                if (Double.TryParse(val, out fs))
                                {
                                    part.mInline.FontSize = fs;
                                }
                            }
                            else if (key.Equals("FontStretch", StringComparison.InvariantCultureIgnoreCase))
                            {
                                FontStretch fs = FontStretches.Normal;
                                try
                                {
                                    fs = (FontStretch)new FontStretchConverter().ConvertFromString(val);
                                }
                                catch (Exception)
                                {
                                    fs = FontStretches.Normal;
                                }
                                part.mInline.FontStretch = fs;
                            }
                            else if (key.Equals("FontStyle", StringComparison.InvariantCultureIgnoreCase))
                            {
                                FontStyle fs = FontStyles.Normal;
                                try
                                {
                                    fs = (FontStyle)new FontStyleConverter().ConvertFromString(val);
                                }
                                catch (Exception)
                                {
                                    fs = FontStyles.Normal;
                                }
                                part.mInline.FontStyle = fs;
                            }
                            else if (key.Equals("FontFamily", StringComparison.InvariantCultureIgnoreCase))
                            {
                                if (!String.IsNullOrEmpty(val))
                                {
                                    FontFamily ff = new FontFamily(val);
                                    if (Fonts.SystemFontFamilies.Contains(ff))
                                    {
                                        part.mInline.FontFamily = ff;
                                    }
                                }
                            }
                            else if (key.Equals("Background", StringComparison.InvariantCultureIgnoreCase))
                            {
                                Brush b = part.mInline.Background;
                                try
                                {
                                    b = (Brush)new BrushConverter().ConvertFromString(val);
                                }
                                catch (Exception)
                                {
                                    b = part.mInline.Background;
                                }
                                part.mInline.Background = b;
                            }
                            else if (key.Equals("Foreground", StringComparison.InvariantCultureIgnoreCase))
                            {
                                Brush b = part.mInline.Foreground;
                                try
                                {
                                    b = (Brush)new BrushConverter().ConvertFromString(val);
                                }
                                catch (Exception)
                                {
                                    b = part.mInline.Foreground;
                                }
                                part.mInline.Foreground = b;
                            }
                            else if (key.Equals("ToolTip", StringComparison.InvariantCultureIgnoreCase))
                            {
                                part.mInline.ToolTip = val;
                            }
                            else if (key.Equals("Text", StringComparison.InvariantCultureIgnoreCase) && part.mInline is Run)
                            {
                                (part.mInline as Run).Text = val;
                            }
                            else if (key.Equals("NavigateUri", StringComparison.InvariantCultureIgnoreCase) && part.mInline is Hyperlink)
                            {
                                (part.mInline as Hyperlink).NavigateUri = new Uri(val);
                            }
                            m2 = m2.NextMatch();
                        }
                    }
    
                    if (part.mInline != null)
                    {
                        if (tag.TrimEnd().EndsWith("/"))
                        {
                            if (prevPart.mChildren != null)
                            {
                                prevPart.mChildren.Add(part.mInline);
                            }
                        }
                        else
                        {
                            parts.Add(part);
                        }
                    }
                }
                lastIdx = m.Index + m.Length;
                m = m.NextMatch();
            }
            if (lastIdx < (len - 1))
            {
                root.mChildren.Add(new Run(s.Substring(lastIdx)));
            }
        }
    }
    
    }
    

提交回复
热议问题