Question

How would I take a Paragraph object and databind them to the TextBlock for use in a DataTemplate? A plain bind does nothing, just a ToString() of the Paragraph object.

The InLines property would let me add a list of TextRun's that make up the Paragraph manually, but that can't be bound to and I could really do with a binding based solution.

Edited question to focus on what I really need to do.

Was it helpful?

Solution

Here's an example using a nested ItemsControl. Unfortunately, it will make one TextBlock per Inline instead of putting the whole Paragraph into one TextBlock:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.Resources>
        <FlowDocument x:Key="document">
            <Paragraph><Run xml:space="preserve">This is the first paragraph.  </Run><Run>The quick brown fox jumps over the lazy dog.</Run></Paragraph>
            <Paragraph><Run xml:space="preserve">This is the second paragraph.  </Run><Run>Two driven jocks help fax my big quiz.</Run></Paragraph>
            <Paragraph><Run xml:space="preserve">This is the third paragraph.  </Run><Run>Sphinx of black quartz, judge my vow!</Run></Paragraph>
        </FlowDocument>
        <DataTemplate DataType="{x:Type Paragraph}">
            <ItemsControl ItemsSource="{Binding Inlines}" IsHitTestVisible="False">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </DataTemplate>
    </Grid.Resources>
    <ListBox ItemsSource="{Binding Blocks, Source={StaticResource document}}"/>
</Grid>

If you want one Paragraph per element you should probably do as suggested and use a read-only RichTextBox, or do what this person did and derive from TextBlock so that the Inlines property can be bound.

OTHER TIPS

I had a similar need and solved it along the lines of Andy's answer... I created a BindableTextBlock:

class BindableTextBlock : TextBlock
{
    public Inline BoundInline
    {
        get { return (Inline)GetValue(BoundInlineProperty); }
        set { SetValue(BoundInlineProperty, value); }
    }

    public static readonly DependencyProperty BoundInlineProperty =
        DependencyProperty.Register("BoundInline", typeof(Inline), typeof(BindableTextBlock),
            new UIPropertyMetadata((PropertyChangedCallback)((d, e) => { ((BindableTextBlock)d).Inlines.Clear(); ((BindableTextBlock)d).Inlines.Add(e.NewValue as Inline); })));
}

Then in my XAML I can bind to the BoundInline dependency property:

    <DataTemplate x:Key="TempTemplate">
        <t:BindableTextBlock TextWrapping="Wrap" BoundInline="{Binding Path=TextInlines}" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" />
    </DataTemplate>

The one drawback to this is that you can only bind a single root Inline to the textblock, which worked fine for my situation as my content is all wrapped in a top-level Span.

I'm not sure if you can bind a Paragraph directly to a TextBlock's inlines. However, I was able to find the class BindableRun that lets you bind to the Run's Text property. Would that work for you instead?

EDIT: Modified my answer to reflect the edited question.

You could try to create your own DataTemplate for Paragraph objects that wraps each one in its own FlowDocument, which is then presented via a RichTextBox (readonly, of course)

I had almost the same problem and answered it in a similar way to joshperry, sub-classing TextBlock to make the inlines Bindable. In addition I wrote a convertor between a String of xaml markup and an InlineCollection.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top