Q: Have you ever tried to embed a
FramworkContentElement
into a
FrameworkElement
inside a WPF template?
Consider the following:
<DataTemplate>
<TableRow>
<TableCell>
<Paragraph>
<FlowDocumnet>
<Paragraph>
This won't work!
</Paragraph>
</FlowDocument>
</Paragraph>
</TableCell>
</TableRow>
</DataTemplate>
I found this problem and solution in the April 2009 ed. of MSDN. The article is about 'Dynamic WPF' How to data bind in flow documents. The problem and solution in the article is how do you create a data bound list item which can be copied and pasted using the windows clipboard in a document? The solution to that goes beyond the topic of this tip and can be found at:
Code for "Create Flexible UIs with Flow Documents And Data Binding"[
^]. However I thought section on creating a '
bridge' between FrameworkElements and FrameworkContentElements was a good candidate for a short tip/trick on WPF.
You may ask your self why build a bridge when there are already bridges hosted in the .NET WPF framework such as:
BlockUIContainer
and
TextBlock
? Well if you need to do more then simple 'in lines' you will need something different other then what the frame work has to offer.
Here is the solution as it appears in MSDN for creating a bridge:
Figure 1 - Fragment Class
[ContentProperty("Content")]
public class Fragment : FrameWorkElement
{
private static readonly DependancyProperty ContentProperty =
DependanceProperty.Register("Content",
typeof(FrameworkContentElement),
typeof(Fragment));
public FrameworkContnetElement Content
{
get
{
return (FrameworkContentElement)GetValue(ContentProperty);
}
set
{
SetValue(ContentProperty, value);
}
}
}
Now the folloing is possible:
<DataTemplate>
<flowdoc:Fragment>
<TableRow>...</TableRow>
</flowdoc:Fragment>
</DataTemplate>
Figure 1 is the bridge which is really just a wrapper for the FrameworkContnetElement. However a helper method is required when displaying the data in the content element. The helper really where the trick is implemented. There is a problem encountered when re displaying the data in the Framework Element. The problem is that when displaying the data an enumerator is created and this causes an exception to be thrown. "Collection Modified..."
Here is the workaround in the help class:
Figure 2 - Helper Method
public static FrameworkContentElement LoadDataTemplate(
DataTemplate dataTemplate)
{
object content = dataTemplate.LoadContent();
if(content is Fragment)
return(FrameworkContentElement)((Fragment)content).Content;
else if(content id TextBlock)
{
InlineCollection inlines = ((TextBlock)content).Inlines;
if(inlines.Count == 1
return inlines.FirstInline;
else
{
Paragraph paragraph = new Parageraph();
while(inlines.FirstInline != null)
paragraph.Inlines.Add(inlines.FirstInline);
return paragraph;
}
}
else
throw new Exception("Data Template needs to contain a <Fragment> or <TextBlock>");
}