Currently I'm designing an application that should at one point be able to create a report from a Xaml template File using Data Binding (involving a FlowDocument
).
The idea was to simply convert a dynamically loaded control via BlockUIContainer to be printable in a FlowDocument.
As long as I load an entire file into a single FrameworkElement
and set the DataContext
property, the Data Binding works like a charm.
foreach (Order order in orders)
{
BlockUIContainer container = new BlockUIContainer();
container.Child = (FrameworkElement)GetOrderControl();
(container.Child as FrameworkElement).DataContext = order;
document.Blocks.Add(container);
}
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.SystemIdle,
new Action(() => { return; }));
All the GetOrderControl()
method does is read from a FileStream
a parse the content via XamlReader.Load()
. The file is structured like this:
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
...
<TextBlock Text="{Binding Path=Country}" />
...
</Gird>
Now the application should add BlockUIContainer
s dynamically according to the dataset. I need to do it in code behind to implement custom pagination, because the reports might get longer than one page.
Since I only want a single template file, I've packed my header, footer and grouping controls all in a single xaml file like this:
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<BlockUIContainer Name="PageHeader">
<Grid ... />
</BlockUIContainer>
<BlockUIContainer Name="Element">
<Grid ... />
</BlockUIContainer>
</FlowDocument>
The <Grid ... />
control inside the "Element" named BlockUIContainer is just exactly the Grid control used in the example before.
Now all I do is get the child of the BlockUIContainer and create a copy of that by saving it to a string and back to a FrameworkElement
and set the DataContext
.
foreach (Order order in orders)
{
BlockUIContainer container = new BlockUIContainer();
container.Child = (FrameworkElement)XamlReader.Parse(XamlWriter.Save(elementControl));
(container.Child as FrameworkElement).DataContext = order;
document.Blocks.Add(container);
}
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.SystemIdle,
new Action(() => { return; }));
Here however the data binding is not evaluating. I tried calling the UpdateLayout()
method on the FrameworkElement
after setting the DataContext
.
That does evaluate at least some Bindings in a <DataTrigger Binding="{Binding Path=DangerousGoods}" />
for a <Style>
Element setting the Visibility of some child controls, but none of the Bindings like <TextBlock Text="{Binding Path=Country}" />
are not evaluated.
I'm at a loss here. How do I get the remaining bindings to work again after parsing them? I don't really want to create several files for one document.