none
Data Binding in Flow Document

    Question

  • 1.       I have some Flow Document Templates, where Binding Information will have to be specified in the Design Time. In the run time a Business Object will be assigned to the Data Context property of Flow Document or any of the Panels (Stack, Dock etc) inside the Flow Document.

     

    2.       Properties of Paragraph, Run or other elements does not seem to have dependency properties, hence I will not be able to specify Binding Info Declaratively. Am  currently wrapping my Content in BlockUIContainers with Text Blocks inside them. The Text Block’s Text property can be used as a placeholder to specify binding information declaratively.

     

    3.       One alternate way to specify Binding for Flow Document Elements that are not enclosed in Block Or Inline UI Containers is to specify a reverse binding (from the controls in the application UI to the Flow Document Elements, where Flow Document Elements will be a Source now and the Binding will be One Way To Source. This increases the number of lines of code for each binding and also the requirement in my assignment is to specify the binding declaratively.

     

    4.        Is Wrapping the Content in BlockUIContainers / InlineUIContainers to specify the Binding Info, the proper approach or is there any better solutions ?.

     

    5.       Also how do we preserve white spaces inside a Flow Document Element ?.

     

    (Note: After all the manipulations, the Flow Document will be converted to XPS in the final step). Thanks in advance.

     

    Monday, October 15, 2007 6:51 PM

All replies

  • 1 - 4 You could try subclassing run and implementing databinding, see http://fortes.com/2007/03/20/bindablerun/

    5 I'm not sure what you mean here perhaps you are looking for the xmlTongue Tiedpace='preserve' attribute?

    <Run xmlTongue Tiedpace='preserve'> some text with preserved leading and trailing space </Run>

     

    --Ifeanyi Echeruo [MSFT]

    Monday, October 15, 2007 9:52 PM
  • Thanks for the response.

     

    I get this error “{”Collection was modified; enumeration operation may not execute.”}” when i use the BindableRun element more than once in my flow document - if i use only once it keeps quiet and works correct- any clues. ???

     

    Wednesday, October 17, 2007 4:00 PM
  • take a look at the post her for the bindable run sample

    http://fortes.com/2007/03/20/bindablerun/

     

    Thursday, October 18, 2007 4:45 AM
    Moderator
  • I have taken the code base only from this POST. I have stated wrongly in my previous post saying it throws up only on the second time. It throws up on the first occurence itself and stops. When i try to bind the Object to the DataContext of Flow Document it throws {"Collection was modified; enumeration operation may not execute."}

     

    Find the Stack Trace and Flow Document Content Below. Please advice.

     

    Stack Trace:

    ---------------------
       at System.Windows.Documents.RangeContentEnumerator.MoveNext()

       at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)

       at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)

       at System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)

       at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)

       at System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)

       at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)

       at System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)

       at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)

       at System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)

       at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)

       at System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)

       at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)

       at System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d)

       at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)

       at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)

       at System.Windows.DescendentsWalker`1.StartWalk(DependencyObject startNode, Boolean skipStartNode)

       at System.Windows.TreeWalkHelper.InvalidateOnInheritablePropertyChange(FrameworkElement fe, FrameworkContentElement fce, InheritablePropertyChangeInfo info, Boolean skipStartNode)

       at System.Windows.FrameworkContentElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)

       at System.Windows.Documents.FlowDocument.OnPropertyChanged(DependencyPropertyChangedEventArgs e)

       at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)

       at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType)

       at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, OperationType operationType, Boolean isInternal)

       at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)

       at System.Windows.FrameworkContentElement.set_DataContext(Object value)

       at AgreementTemplates.EAStep1.SetBinding(Object sender, RoutedEventArgs e) in C:\Documents and Settings\a-devnat\My Documents\Visual Studio 2005\Projects\AgreementTemplates\AgreementTemplates\EAStep1.xaml.cs:line 59
    ---------------------------
    OK  
    ---------------------------

     

    Here is the flow document content.

    <FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    ColumnWidth="400" FontFamily="Arial" FontSize="12"

    xmlns:bt="clr-namespace:AgreementTemplates;assembly=AgreementTemplates">

    <Section Name="A">

    <Paragraph FontSize="20" Block.TextAlignment="Right">

    <Bold FontStyle="Italic" Block.TextAlignment="Right">Microsoft</Bold>

    |<Bold Block.TextAlignment="Right">Volume Licensing</Bold>

    </Paragraph>

    <Paragraph FontSize="20">

    <bt:BindableRun BoundText="{Binding Path=Program}" Name="Program"></bt:BindableRun>

    <Run>Agreement</Run>

    </Paragraph>

    <Table>

    <Table.Columns>

    <TableColumn />

    <TableColumn />

    <TableColumn />

    </Table.Columns>

    <TableRowGroup>

    <TableRow>

    <TableCell>

    <Paragraph>

    <Run>Agreement #:</Run>

    <Run>V2404948</Run>

    </Paragraph>

    </TableCell>

    <TableCell>

    <Paragraph>

    <Run>Previous Agreement #:</Run>

    <bt:BindableRun BoundText="{Binding Path=PreviousAgreementNumber1}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    </TableRowGroup>

    </Table>

    <Paragraph>

    This <Run>

    <!--<bt:BindableRun BoundText="{Binding Path=Program}"></bt:BindableRun>//-->

    </Run> Agreement is entered into between Customer and Microsoft as of the effective date.

    </Paragraph>

    <Paragraph>

    <Bold FontSize="15">Customer Information</Bold>

    </Paragraph>

    <Table>

    <Table.Columns>

    <TableColumn />

    </Table.Columns>

    <TableRowGroup>

    <TableRow>

    <TableCell>

    <Paragraph>

    <Run>Customer ID:</Run>

    <bt:BindableRun BoundText="{Binding Path=CustomerID}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <bt:BindableRun BoundText="{Binding Path=CustomerContactName}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <bt:BindableRun BoundText="{Binding Path=CompanyName}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <bt:BindableRun BoundText="{Binding Path=CustomerAddress1}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <bt:BindableRun BoundText="{Binding Path=CustomerAddress2}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <bt:BindableRun BoundText="{Binding Path=CustomerCity}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <bt:BindableRun BoundText="{Binding Path=CustomerCountry}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <Run>Telephone:</Run>

    <bt:BindableRun BoundText="{Binding Path=CustomerPhone}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <Run>Fax:</Run>

    <bt:BindableRun BoundText="{Binding Path=CustomerFax}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    <TableRow>

    <TableCell>

    <Paragraph>

    <Run>Email:</Run>

    <bt:BindableRun BoundText="{Binding Path=CustomerEmail}"></bt:BindableRun>

    </Paragraph>

    </TableCell>

    </TableRow>

    </TableRowGroup>

    </Table>

    <Paragraph>

    The personal information Customer provides in connection with

    this agreement will be used and protected according to the privacy statement available at

    <Hyperlink NavigateUri="http://licensing.microsoft.com">http://licensing.microsoft.com</Hyperlink>.

    </Paragraph>

    </Section>

    </FlowDocument>

    Thursday, October 18, 2007 4:24 PM
  • My first hunch is the binding changes the state of the run at a bad time.

     

    Try delaying when you set the Text inside the PropertyChanged callback by calling BeginInvoke.

    i.e

    Instead of

    ((Run) d).Text = (string) e.NewValue;

    Try

     

    this.Dispatcher.BeginInvoke(

    DispatcherPriority.Normal,

    new DispatcherOperationCallback(

    delegate(object arg) {

    ((Run) d).Text = (string) e.NewValue;

    return null;

    }

    ),

    null

    );

     

    --Ifeanyi Echeruo [MSFT]

    Friday, October 19, 2007 6:45 AM
  •      I cannot reproduce this problem, since I am using fairly simple business object. could you please post your business object code here to help us further diagnose the potential causes of this problem.

    Thanks

     

    Friday, October 19, 2007 7:59 AM
  • BeginInvoke is a good workaround to the "Collection was modified" issue, but we've discovered another workaround that prevents the flicker that BeginInvoke can cause in some circumstances:

    <TextBlock>Name: <bt:BindableRun BoundText="{Binding Name}"

        DataContext="{Binding DataContext, RelativeSource=

        {RelativeSource AncestorType=FrameworkElement}}" />

    </TextBlock>


    http://code.logos.com/blog/2008/01/data_binding_in_a_flowdocument.html
    Friday, January 11, 2008 10:53 PM