Comment lier un texte à une ressource contenant du texte formaté?

j'ai un texte dans ma fenêtre WPF.

 <TextBlock>
     Some <Bold>formatted</Bold> text.
 </TextBlock>

quand il est rendu il ressemble à ceci,

Certains formatés du texte.

ma question Est, puis-je lier ce" contenu " en ligne à une ressource dans ma demande?

j'ai obtenu d'aussi loin que:

Faire une demande de ressources de la chaîne,

myText="Some <Bold>formatted</Bold> text."

et le xaml suivant (certains codes ont été omis par souci de brièveté)

 <Window xmlns:props="clr-namespace:MyApp.Properties">
     <Window.Resources>
         <props:Resources x:Key="Resources"/>
     </Window.Resources>
      <TextBlock x:Name="Try1" 
          Text="{Binding Source={StaticResource Resources} Path=myText}"/>
     <TextBlock x:Name="Try2">
          <Binding Source="{StaticResource Resources}" Path="myText" />
     </TextBlock>
 </Window>

Try1 rend avec les balises en place et ne pas effectuer la mise en forme.

Certains formaté texte.

Try2 ne compilera ni ne rendra car la ressource "myText" n'est pas de type Inline mais une chaîne de caractères.

est-ce que cette tâche apparemment simple est possible et si oui comment?

23
demandé sur Jodrell 2011-04-06 15:52:48

6 réponses

Voici mon code modifié pour le format récursif du texte. Il gère les caractères gras, italiques, soulignés et LineBreak mais peut facilement être étendu pour supporter plus (modifier le switch statement).

public static class MyBehavior
{
    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(MyBehavior),
        new UIPropertyMetadata("", FormattedTextChanged));

    static Inline Traverse(string value)
    {
        // Get the sections/inlines
        string[] sections = SplitIntoSections(value);

        // Check for grouping
        if (sections.Length.Equals(1))
        {
            string section = sections[0];
            string token; // E.g <Bold>
            int tokenStart, tokenEnd; // Where the token/section starts and ends.

            // Check for token
            if (GetTokenInfo(section, out token, out tokenStart, out tokenEnd))
            {
                // Get the content to further examination
                string content = token.Length.Equals(tokenEnd - tokenStart) ?
                    null :
                    section.Substring(token.Length, section.Length - 1 - token.Length * 2);

                switch (token)
                {
                    case "<Bold>":
                        return new Bold(Traverse(content));
                    case "<Italic>":
                        return new Italic(Traverse(content));
                    case "<Underline>":
                        return new Underline(Traverse(content));
                    case "<LineBreak/>":
                        return new LineBreak();
                    default:
                        return new Run(section);
                }
            }
            else return new Run(section);
        }
        else // Group together
        {
            Span span = new Span();

            foreach (string section in sections)
                span.Inlines.Add(Traverse(section));

            return span;
        }
    }

    /// <summary>
    /// Examines the passed string and find the first token, where it begins and where it ends.
    /// </summary>
    /// <param name="value">The string to examine.</param>
    /// <param name="token">The found token.</param>
    /// <param name="startIndex">Where the token begins.</param>
    /// <param name="endIndex">Where the end-token ends.</param>
    /// <returns>True if a token was found.</returns>
    static bool GetTokenInfo(string value, out string token, out int startIndex, out int endIndex)
    {
        token = null;
        endIndex = -1;

        startIndex = value.IndexOf("<");
        int startTokenEndIndex = value.IndexOf(">");

        // No token here
        if (startIndex < 0)
            return false;

        // No token here
        if (startTokenEndIndex < 0)
            return false;

        token = value.Substring(startIndex, startTokenEndIndex - startIndex + 1);

        // Check for closed token. E.g. <LineBreak/>
        if (token.EndsWith("/>"))
        {
            endIndex = startIndex + token.Length;
            return true;
        }

        string endToken = token.Insert(1, "/");

        // Detect nesting;
        int nesting = 0;
        int temp_startTokenIndex = -1;
        int temp_endTokenIndex = -1;
        int pos = 0;
        do
        {
            temp_startTokenIndex = value.IndexOf(token, pos);
            temp_endTokenIndex = value.IndexOf(endToken, pos);

            if (temp_startTokenIndex >= 0 && temp_startTokenIndex < temp_endTokenIndex)
            {
                nesting++;
                pos = temp_startTokenIndex + token.Length;
            }
            else if (temp_endTokenIndex >= 0 && nesting > 0)
            {
                nesting--;
                pos = temp_endTokenIndex + endToken.Length;
            }
            else // Invalid tokenized string
                return false;

        } while (nesting > 0);

        endIndex = pos;

        return true;
    }

    /// <summary>
    /// Splits the string into sections of tokens and regular text.
    /// </summary>
    /// <param name="value">The string to split.</param>
    /// <returns>An array with the sections.</returns>
    static string[] SplitIntoSections(string value)
    {
        List<string> sections = new List<string>();

        while (!string.IsNullOrEmpty(value))
        {
            string token;
            int tokenStartIndex, tokenEndIndex;

            // Check if this is a token section
            if (GetTokenInfo(value, out token, out tokenStartIndex, out tokenEndIndex))
            {
                // Add pretext if the token isn't from the start
                if (tokenStartIndex > 0)
                    sections.Add(value.Substring(0, tokenStartIndex));

                sections.Add(value.Substring(tokenStartIndex, tokenEndIndex - tokenStartIndex));
                value = value.Substring(tokenEndIndex); // Trim away
            }
            else
            { // No tokens, just add the text
                sections.Add(value);
                value = null;
            }
        }

        return sections.ToArray();
    }

    private static void FormattedTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        string value = e.NewValue as string;

        TextBlock textBlock = sender as TextBlock;

        if (textBlock != null)
            textBlock.Inlines.Add(Traverse(value));
    }
}

modifier: (proposé par Spook)

une version plus courte, mais exige que le texte soit XML-valide:

using System.Xml;

// (...)

public static class TextBlockHelper
{
    #region FormattedText Attached dependency property

    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(TextBlockHelper),
        new UIPropertyMetadata("", FormattedTextChanged));

    private static void FormattedTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        string value = e.NewValue as string;

        TextBlock textBlock = sender as TextBlock;

        if (textBlock != null)
        {
            textBlock.Inlines.Clear();
            textBlock.Inlines.Add(Process(value));
        }
    }

    #endregion

    static Inline Process(string value)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(value);

        Span span = new Span();
        InternalProcess(span, doc.ChildNodes[0]);

        return span;
    }

    private static void InternalProcess(Span span, XmlNode xmlNode)
    {
        foreach (XmlNode child in xmlNode)
        {
            if (child is XmlText)
            {
                span.Inlines.Add(new Run(child.InnerText));
            }
            else if (child is XmlElement)
            {
                switch (child.Name.ToUpper())
                {
                    case "B":
                    case "BOLD":
                        {
                            Span boldSpan = new Span();
                            InternalProcess(boldSpan, child);
                            Bold bold = new Bold(boldSpan);
                            span.Inlines.Add(bold);
                            break;
                        }
                    case "I":
                    case "ITALIC":
                        {
                            Span italicSpan = new Span();
                            InternalProcess(italicSpan, child);
                            Italic italic = new Italic(italicSpan);
                            span.Inlines.Add(italic);
                            break;
                        }
                    case "U":
                    case "UNDERLINE":
                        {
                            Span underlineSpan = new Span();
                            InternalProcess(underlineSpan, child);
                            Underline underline = new Underline(underlineSpan);
                            span.Inlines.Add(underline);
                            break;
                        }
                }
            }
        }
    }
}

Et un exemple d'utilisation:

<RootItem xmlns:u="clr-namespace:MyApp.Helpers">
    <TextBlock u:TextBlockHelper.FormattedText="{Binding SomeProperty}" />
</RootItem>
26
répondu Vincent 2015-01-02 19:20:32

Que Diriez-vous d'utiliser le comportement attaché? Le code ci-dessous ne traite que les étiquettes en caractères gras. Chaque mot qui devrait être gras doit être enveloppé dans des étiquettes en gras. Vous voudrez probablement faire la classe d'accepter d'autres formats. De plus, les espaces doivent être mieux manipulés, la classe élimine les espaces consécutifs et ajoute un supplément à la fin. Ainsi, considérez la classe ci-dessous comme code de démonstration seulement qui aura besoin de plus de travail pour être utile, mais il devrait vous aider à commencer.

XAML:

<Window x:Class="FormatTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:FormatTest="clr-namespace:FormatTest"
    Title="Window1" Height="300" Width="300">

    <TextBlock FormatTest:FormattedTextBehavior.FormattedText="{Binding Path=Text}" />

</Window>

Code derrière:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace FormatTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            DataContext = this;
        }

        public string Text { get { return "Some <Bold>formatted</Bold> text."; } }
    }

    public static class FormattedTextBehavior
    {
        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;
            string value = e.NewValue as string;
            string[] tokens = value.Split(' ');
            foreach (string token in tokens)
            {
                if (token.StartsWith("<Bold>") && token.EndsWith("</Bold>"))
                {
                    textBlock.Inlines.Add(new Bold(new Run(token.Replace("<Bold>", "").Replace("</Bold>", "") + " ")));
                }
                else
                {
                    textBlock.Inlines.Add(new Run(token + " "));
                }
            }
        }
    }
}
4
répondu Wallstreet Programmer 2011-04-07 00:30:09

EDIT:

Cette ligne,

<props:Resources x:Key="Resources"/>

est une mauvaise approche pour accéder au projet.Propriété.Les ressources de l'espace de noms. Il provoque des problèmes lors de la recompilation.

beaucoup mieux utiliser x:Static pour faire quelque chose comme ça,

Text="{x:Static props:Resources.SomeText}"

dans votre reliure. Thx à Ben


OK, c'est comme ça que je l'ai fait. Il n'est pas parfait, mais il fonctionne.

rappelez-vous qu'il existe une ressource de projet appelée FormattedText.

c:

// TextBlock with a bindable InlineCollection property.

// Type is List(Inline) not InlineCollection becuase
// InlineCollection makes the IDE xaml parser complain
// presumably this is caused by an inherited attribute.

public class BindableTextBlock : TextBlock
{
    public static readonly DependencyProperty InlineCollectionProperty =
        DependencyProperty.Register(
            "InlineCollection",
            typeof(List<Inline>),
            typeof(BindableTextBlock),
            new UIPropertyMetadata(OnInlineCollectionChanged));

    private static void OnInlineCollectionChanged(DependencyObject sender,
        DependencyPropertyChangedEventArgs e)
    {
        BinableTextBlock instance = sender as BindableTextBlock;

        if (instance != null)
        {
            List<Inline> newText = e.NewValue as List<Inline>;
            if (newText != null)
            {
                // Clear the underlying Inlines property
                instance.Inlines.Clear();
                // Add the passed List<Inline> to the real Inlines
                instance.Inlines.AddRange(newText.ToList());
            }
        }
    }

    public List<Inline> InlineCollection
    {
        get
        {
            return (List<Inline>)GetValue(InlineCollectionProperty);
        }
        set
        {
            SetValue(InlineCollectionProperty, value);
        }
    }
}

// Convertor between a string of xaml with implied run elements
// and a generic list of inlines

[ValueConversion(typeof(string), typeof(List<Inline>))]
public class StringInlineCollectionConvertor : IValueConverter
{
    public object Convert(object value, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    {
        string text = value as String;

        // a surrogate TextBlock to host an InlineCollection
        TextBlock results = new TextBlock();

        if (!String.IsNullOrEmpty(text))
        {
            //Arbritary literal acting as a replace token, 
            //must not exist in the empty xaml definition.
            const string Replace = "xxx";

            // add a dummy run element and replace it with the text
            results.Inlines.Add(new Run(Replace));
            string resultsXaml = XamlWriter.Save(results);
            string resultsXamlWithText = resultsXaml.Replace(Replace, text);

            // deserialise the xaml back into our TextBlock
            results = XamlReader.Parse(resultsXamlWithText) as TextBlock;
        }
        return results.Inlines.ToList<Inline>();
    }

    // Not clear when this will be called but included for completeness

    public object ConvertBack(
        object value, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    {
        String results = String.Empty;

        InlineCollection inlines = value as InlineCollection;
        if (inlines != null)
        {
            //read the xaml as xml and return the "content"
            var reader = 
                XElement.Parse(XamlWriter.Save(inlines)).CreateReader();
            reader.MoveToContent();
            results = reader.ReadInnerXml();
        }
        return results;
    }
}

xaml:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:props="clr-namespace:Project.Properties"
    xmlns:local="clr-namespace:Project">
    <Window.Resources>
        <props:Resources x:Key="Resources"/>
        <local:StringInlineCollectionConvertor x:Key="InlineConvert"/>
    </Window.Resources>
    <local:BindableTextBlock InlineCollection="
        {Binding Source={StaticResource Resources}, 
        Path=FormattedText, 
        Converter={StaticResource InlineConvert}}"/>
</Window>

j'ai fait 2 classes. Un texte sous-classéavec un collecteur inlinecollection "bindable" et un convertisseur IValueConverter pour convertir la collection à partir et vers une chaîne.

utilisant la collecte en ligne directement comme type de la propriété fait VS2010 se plaindre, bien que le code a quand même bien fonctionné. J'ai changé pour une liste générique D'Inlines. Je suppose qu'il y a un attribut héréditaire disant À VS que la collecte en ligne n'a pas de constructeur.

j'ai essayé de prise de la InlineCollection propriété de la BindableTextBlock de ContentProperty mais a couru dans les questions et hors du temps. N'hésitez pas à passer à l'étape suivante et à m'en parler.

Je m'excuse pour n'importe quelle erreur mais ce code a eu pour être transcrit et à désinfecter.

S'il y a une meilleure façon de faire cela, sûrement il doit y avoir, s'il vous plaît dites-le moi aussi. Ce ne serait pas bien si cette fonctionnalité était intégrée ou, Ai-je manqué quelque chose?

2
répondu Jodrell 2017-05-23 11:54:06

j'ai fini par avoir besoin de faire ceci dans mon application et j'ai dû supporter beaucoup de la marge normalement possible dans les lignes de texte, donc J'ai pris la réponse de programmeur de Wallstreet ci-dessus (qui fonctionne magnifiquement et est beaucoup moins compliquée que la plupart des autres réponses que j'ai trouvées sur ce sujet) et a élargi sur elle. Je pense que quelqu'un d'autre pourrait trouver ça utile.

Je n'ai pas encore testé toutes les étiquettes, mais toutes celles que j'ai testées ont fonctionné comme un charme. J'ai aussi je soupçonne que ce n'est pas le code le plus rapide au monde, mais mes propres tests avec plusieurs milliers de messages formatés dans un ListView ont semblé étonnamment zippés. YMMV. Le Code est le suivant:

XAML:

<Window x:Class="FormatTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:FormatTest="clr-namespace:FormatTest"
    Title="Window1" Height="300" Width="300">

    <TextBlock FormatTest:FormattedTextBehavior.FormattedText="{Binding Path=Text}" />

</Window>

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(@"<(?<Span>/?[^>]*)>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    private static Regex mSpanRegex = new Regex("(?<Key>[^\s=]+)=\"(?<Val>[^\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<TextPart> parts = new List<TextPart>();
        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 </" + part.mType + ">) 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)));
        }
    }
}

}
2
répondu devnullicus 2015-04-16 04:06:50

la même chose que j'ai implémenté en utilisant Behavior. Code indiqué ci-dessous:

public class FormatTextBlock : Behavior<System.Windows.Controls.TextBlock>
{
    public static readonly DependencyProperty FormattedTextProperty = 
        DependencyProperty.Register(
            "FormattedText", 
            typeof(string),
            typeof(FormatTextBlock),
            new PropertyMetadata(string.Empty, OnFormattedTextChanged));

    public string FormattedText
    {
        get { return (string)AssociatedObject.GetValue(FormattedTextProperty); }
        set { AssociatedObject.SetValue(FormattedTextProperty, value); }
    }

    private static void OnFormattedTextChanged(DependencyObject textBlock, DependencyPropertyChangedEventArgs eventArgs)
    {
        System.Windows.Controls.TextBlock currentTxtBlock = (textBlock as FormatTextBlock).AssociatedObject;

        string text = eventArgs.NewValue as string;

        if (currentTxtBlock != null)
        {
            currentTxtBlock.Inlines.Clear();

            string[] strs = text.Split(new string[] { "<Bold>", "</Bold>" }, StringSplitOptions.None);

            for (int i = 0; i < strs.Length; i++)
            {
                currentTxtBlock.Inlines.Add(new Run { Text = strs[i], FontWeight = i % 2 == 1 ? FontWeights.Bold : FontWeights.Normal });
            }
        }
    }
}

XAML - importer l'espace de noms

<UserControl x:Class="MyClass"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:behav="clr-namespace:myAssembly.myNameSapce;assembly=myAssembly"
>

ensuite pour utiliser le comportement comme:

    <TextBlock TextWrapping="Wrap">
        <i:Interaction.Behaviors>
            <behav:FormatTextBlock FormattedText="{Binding Path=UIMessage}" />
        </i:Interaction.Behaviors>
    </TextBlock>
2
répondu Malu MN 2016-01-13 05:54:14

ce travail pour moi:

XAML:

<phone:PhoneApplicationPage x:Class="MyAPP.Views.Class"
                        xmlns:utils="clr-namespace:MyAPP.Utils">

and your Textlock XAML:

<TextBlock utils:TextBlockHelper.FormattedText="{Binding Text}" />

CODE:

public static class TextBlockHelper
{
    public static string GetFormattedText(DependencyObject textBlock)
    { 
        return (string)textBlock.GetValue(FormattedTextProperty); 
    }

    public static void SetFormattedText(DependencyObject textBlock, string value)
    { 
        textBlock.SetValue(FormattedTextProperty, value); 
    }

    public static readonly DependencyProperty FormattedTextProperty =
        DependencyProperty.RegisterAttached("FormattedText", typeof(string), typeof(TextBlock),
        new PropertyMetadata(string.Empty, (sender, e) =>
        {
            string text = e.NewValue as string;
            var textB1 = sender as TextBlock;
            if (textB1 != null)
            {
                textB1.Inlines.Clear();
                var str = text.Split(new string[] { "<b>", "</b>" }, StringSplitOptions.None);
                for (int i = 0; i < str.Length; i++)
                    textB1.Inlines.Add(new Run { Text = str[i], FontWeight = i % 2 == 1 ? FontWeights.Bold : FontWeights.Normal });

            }
        }));
}

utiliser dans votre chaîne de liaison:

String Text = Text <b>Bold</b>;
0
répondu Rodrigo Rodrigues 2015-05-25 16:39:12