Search code examples
c#wpfformattingtextblockparagraph

How to inject a formatted paragraph into a TextBlock?


I'm trying to transmit the formatted content of a paragraph to a TextBlock, but the formatting disappears:

// Create a formatted paragraph
Paragraph para = new Paragraph();
para.FontSize = 25;
para.FontWeight = FontWeights.Bold;
para.Inlines.Add(new Run("Text of paragraph."));

// Create a span with the content of the paragraph (FontSize 25 and FontWeight Bold stay alive)
Span span = new Span(para.ContentStart, para.ContentEnd);

// Create a TextBlock with the span (FontSize 25 and FontWeight Bold get lost)
TextBlock textBlock = new TextBlock();
textBlock.Inlines.Add(span);

What could be done to keep the formatting? Thanks in advance.

Update
The formatting of the paragraph is known at runtime, so I can't apply property values one by one manually.

Update 2
The background of the question is that I want to measure the length of formatted paragraphs if they are stretched to one line. This can be done by a TextBlock. The paragraphs are located in TableCells, I want to adjust the column widths automatically.


Solution

  • I reached the following solution:

    // Create a formatted Paragraph
    Paragraph para = new Paragraph();
    para.FontSize = 25;
    para.FontWeight = FontWeights.Bold;
    para.Inlines.Add(new Run("Text of paragraph."));
    
    // Clone all Inlines
    List<Inline> clonedInlines = new List<Inline>();
    foreach (Inline inline in para.Inlines)
    {
        Inline clonedInline = ElementClone<Inline>(inline);
        clonedInlines.Add(clonedInline);
    }
    
    // Get all Paragraph properties with a set value
    List<DependencyProperty> depProps = DepPropsGet(para, PropertyFilterOptions.SetValues);
    
    // Apply the Paragraph values to each Inline
    foreach (DependencyProperty depProp in depProps)
    {
        object propValue = para.GetValue(depProp);
    
        foreach (Inline clonedInline in clonedInlines)
        {
            // Can the Inline have the value?
            if (depProp.OwnerType.IsAssignableFrom(typeof(Inline)))
            {
                // Apply the Paragraph value
                clonedInline.SetValue(depProp, propValue);
            }
        }
    }
    
    // Create a TextBlock with the same properties as the Paragraph
    TextBlock textBlock = new TextBlock();
    textBlock.Inlines.AddRange(clonedInlines);
    
    /// <summary>
    /// Cloner.
    /// </summary>
    public static T ElementClone<T>(T element)
    {
        // Element to Stream
        MemoryStream memStream = new MemoryStream();
        XamlWriter.Save(element, memStream);
    
        // Cloned element from Stream
        object clonedElement = null;
        if (memStream.CanRead)
        {
            memStream.Seek(0, SeekOrigin.Begin);
            clonedElement = XamlReader.Load(memStream);
            memStream.Close();
        }
        return (T)clonedElement;
    }
    
    /// <summary>
    /// Property-Getter.
    /// </summary>
    public static List<DependencyProperty> DepPropsGet(DependencyObject depObj, PropertyFilterOptions filter)
    {
        List<DependencyProperty> result = new List<DependencyProperty>();
    
        foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(depObj, new Attribute[] { new PropertyFilterAttribute(filter) }))
        {
            DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd);
    
            if (dpd != null)
            {
                result.Add(dpd.DependencyProperty);
            }
        }
    
        return result;
    }