Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>EDIT:</p> <p>This line,</p> <p><code>&lt;props:Resources x:Key="Resources"/&gt;</code></p> <p>is a bad approach to accesing the Project.Properties.Resources namespace. It causes awkward glitches when recompiling.</p> <p>Much better to use <code>x:Static</code> to do somthing like this,</p> <p><code>Text="{x:Static props:Resources.SomeText}"</code></p> <p>in your binding. Thx to <a href="https://stackoverflow.com/questions/665764/how-to-fetch-string-from-resource-to-assign-in-wpf-resource-section-in-xaml">Ben</a></p> <hr> <p>Okay, this is how I did it. It's not perfect but it works.</p> <p>Remember, there is a project resource called FormattedText.</p> <p>cs:</p> <pre class="lang-cs prettyprint-override"><code>// 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&lt;Inline&gt;), typeof(BindableTextBlock), new UIPropertyMetadata(OnInlineCollectionChanged)); private static void OnInlineCollectionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { BinableTextBlock instance = sender as BindableTextBlock; if (instance != null) { List&lt;Inline&gt; newText = e.NewValue as List&lt;Inline&gt;; if (newText != null) { // Clear the underlying Inlines property instance.Inlines.Clear(); // Add the passed List&lt;Inline&gt; to the real Inlines instance.Inlines.AddRange(newText.ToList()); } } } public List&lt;Inline&gt; InlineCollection { get { return (List&lt;Inline&gt;)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&lt;Inline&gt;))] 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&lt;Inline&gt;(); } // 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; } } </code></pre> <p>xaml:</p> <pre class="lang-xml prettyprint-override"><code>&lt;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"&gt; &lt;Window.Resources&gt; &lt;props:Resources x:Key="Resources"/&gt; &lt;local:StringInlineCollectionConvertor x:Key="InlineConvert"/&gt; &lt;/Window.Resources&gt; &lt;local:BindableTextBlock InlineCollection=" {Binding Source={StaticResource Resources}, Path=FormattedText, Converter={StaticResource InlineConvert}}"/&gt; &lt;/Window&gt; </code></pre> <p>I made 2 classes. A sub-classed TextBlock with a "bindable" InlineCollection and an IValueConverter to convert the collection from and to a String.</p> <p>Using InlineCollection directly as the type of the property made VS2010 complain, although the code still ran fine. I changed to a generic list of Inlines. I assume that there is an inherited attribute telling VS that the InlineCollection has no constructor.</p> <p>I tryed making the InlineCollection property the BindableTextBlock's ContentProperty but ran into issues and out of time. Please feel free to take the next step and tell me about it.</p> <p>I apologise for any errata but this code had to be transcribed and sanitised.</p> <p>If there is a better way of doing this, surely there must be, please tell me that too. Wouldn't it be nice if this functionality was built in or, have I missed something?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload