How would I databind a Paragraph to a TextBlock?

纵然是瞬间 提交于 2019-12-04 09:50:28

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.

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)

Jodrell

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?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!