Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用richtextbox';s作为itemscontrol运行_C#_Wpf_Xaml_Mvvm - Fatal编程技术网

C# 使用richtextbox';s作为itemscontrol运行

C# 使用richtextbox';s作为itemscontrol运行,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,显示“动态”数据的简单方法是使用ItemsControl(例如,使用WrapPanel作为项目模板) 现在我希望对于我的应用程序,一个充满运行的富文本框是理想的。-运行次数(数量和数据)取决于我的viewmodel中的可观察集合。如果我使用WrapPanel而不是RichTextBox的话,itemscontrol代码如下所示: <ItemsControl ItemsSource="{Binding Data}"> <ItemsControl.ItemsPanel>

显示“动态”数据的简单方法是使用
ItemsControl
(例如,使用
WrapPanel
作为项目模板)

现在我希望对于我的应用程序,一个充满运行的富文本框是理想的。-运行次数(数量和数据)取决于我的viewmodel中的可观察集合。如果我使用
WrapPanel
而不是
RichTextBox
的话,itemscontrol代码如下所示:

<ItemsControl ItemsSource="{Binding Data}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel IsItemsHost="True">
            </WrapPanel>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

现在我尝试在usercontrol中使用richtextbox,usercontrol的xaml如下所示:

<UserControl x:Class="testit.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:testit"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type local:DispData}">
            <TextBlock>
                <Run Text="{Binding Text}"></Run>
            </TextBlock>
        </DataTemplate>
    </UserControl.Resources>
    <StackPanel>
        <RichTextBox IsReadOnly="True" IsDocumentEnabled="True" VerticalScrollBarVisibility="Auto">
            <FlowDocument>
                <ItemsControl ItemsSource="{Binding Data}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Paragraph IsItemsHost="True">
                            </Paragraph>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </FlowDocument>
        </RichTextBox>
        <ItemsControl ItemsSource="{Binding Data}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True">
                    </WrapPanel>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </StackPanel>
</UserControl>

绑定到usercontrol的datacontext的viewmodel是:

namespace testit
{
    class ViewModel : INotifyPropertyChanged
    {

        private readonly ObservableCollection<DispData> _data =
            new ObservableCollection<DispData>();
        public ReadOnlyObservableCollection<DispData> Data { get; private set; }
        public ViewModel() {
            Data = new ReadOnlyObservableCollection<DispData>(_data);
            _data.Add(new DispData("hello"));
            _data.Add(new DispData("world"));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
namespace testit
{
类ViewModel:INotifyPropertyChanged
{
私有只读可观察收集数据=
新的可观察集合();
public ReadOnlyObservableCollection数据{get;private set;}
公共视图模型(){
数据=新的ReadOnlyObservableCollection(_数据);
_添加(新的DispData(“hello”));
_添加(新的DispData(“世界”);
}
公共事件属性更改事件处理程序属性更改;
[NotifyPropertyChangedInvocator]
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null){
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
这会导致
RichTextBox
(第一个错误是,
ItemsControl
不能放在那里,但另一个错误是,
段落
没有
IsItemsHost
属性。--我还想强调,如果我注释掉richtextbox xaml,则包装面板的xaml会起作用:因此这不是绑定或任何错误

RichTextBox
甚至可以与
ItemsControl
一起使用吗?如果不能,我将如何以MVVM方式填充文本框的内容?

您应该查看如何编写与
FlowDocument
RichTextBox
兼容的自己的items控件。代码示例可以在这里找到

下载控件后,按如下所示更新
ItemsContent
GenerateContent()
方法中的if-else条件,以添加对
段落和
内联线的支持

private void GenerateContent(DataTemplate itemsPanel, DataTemplate itemTemplate, IEnumerable itemsSource)
{

....

    if (panel is Section)
        ((Section)panel).Blocks.Add(Helpers.ConvertToBlock(data, element));
    else if (panel is TableRowGroup)
        ((TableRowGroup)panel).Rows.Add((TableRow)element);
    else if (panel is Paragraph && element is Inline)
        ((Paragraph)panel).Inlines.Add((Inline)element);
    else
        throw new Exception(String.Format("Don't know how to add an instance of {0} to an instance of {1}", element.GetType(), panel.GetType()));
并将您的XAML更新为:

<RichTextBox IsReadOnly="True" IsDocumentEnabled="True" VerticalScrollBarVisibility="Auto">
    <FlowDocument>
        <flowdoc:ItemsContent ItemsSource ItemsSource="{Binding Data}">                
            <flowdoc:ItemsContent.ItemsPanel>
                <DataTemplate>
                    <flowdoc:Fragment>
                        <Paragraph flowdoc:Attached.IsItemsHost="True" />
                    </flowdoc:Fragment>
                </DataTemplate>
            </flowdoc:ItemsContent.ItemsPanel>
            <flowdoc:ItemsContent.ItemTemplate>
                <DataTemplate>
                    <flowdoc:Fragment>
                        <flowdoc:BindableRun BoundText="{Binding Text}" />
                    </flowdoc:Fragment>
                </DataTemplate>
            </flowdoc:ItemsContent.ItemTemplate>
        </flowdoc:ItemsContent>
    </FlowDocument>
</RichTextBox>
  • 接下来需要的是将容器控件标记为items host的功能;这可以通过定义附加属性来完成

    public class Attached
    {
        private static readonly DependencyProperty IsItemsHostProperty = DependencyProperty.RegisterAttached("IsItemsHost", typeof(bool), typeof(Attached), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.NotDataBindable, OnIsItemsHostChanged));
        private static readonly DependencyProperty ItemsHostProperty = DependencyProperty.RegisterAttached("ItemsHost", typeof(FrameworkContentElement), typeof(Attached), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.NotDataBindable));
    
        public static bool GetIsItemsHost(DependencyObject target)
        {
            return (bool)target.GetValue(IsItemsHostProperty);
        }
    
    
        public static void SetIsItemsHost(DependencyObject target, bool value)
        {
            target.SetValue(IsItemsHostProperty, value);
        }
    
    
        private static void SetItemsHost(FrameworkContentElement element)
        {
            FrameworkContentElement parent = element;
            while (parent.Parent != null)
                parent = (FrameworkContentElement)parent.Parent;
            parent.SetValue(ItemsHostProperty, element);
        }
    
    
        public static FrameworkContentElement GetItemsHost(DependencyObject dp)
        {
            return (FrameworkContentElement)dp.GetValue(ItemsHostProperty);
        }
    
        private static void OnIsItemsHostChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                FrameworkContentElement element = (FrameworkContentElement)d;
                if (element.IsInitialized)
                    SetItemsHost(element);
                else
                    element.Initialized += ItemsHost_Initialized;
            }
        }
    
        private static void ItemsHost_Initialized(object sender, EventArgs e)
        {
            FrameworkContentElement element = (FrameworkContentElement)sender;
            element.Initialized -= ItemsHost_Initialized;
            SetItemsHost(element);
        }
    } 
    
  • 一个片段控件,可用于将
    FrameworkContentElement
    嵌入
    DataTemplate

    [ContentProperty("Content")]
    public class Fragment : FrameworkElement
    {
        private static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(FrameworkContentElement), typeof(Fragment));
    
        public FrameworkContentElement Content
        {
            get
            {
                return (FrameworkContentElement)GetValue(ContentProperty);
            }
            set
            {
                SetValue(ContentProperty, value);
            }
        }
    }
    
  • 最后,物品控制自身:,完成主要的重物搬运:

    public class ItemsContent : Section
    {
        private static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ItemsContent), new PropertyMetadata(OnItemsSourceChanged));
        private static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(ItemsContent), new PropertyMetadata(OnItemTemplateChanged));
        private static readonly DependencyProperty ItemsPanelProperty = DependencyProperty.Register("ItemsPanel", typeof(DataTemplate), typeof(ItemsContent), new PropertyMetadata(OnItemsPanelChanged));
    
        public ItemsContent()
        {
            Helpers.FixupDataContext(this);
            Loaded += ItemsContent_Loaded;
        }
    
        private void ItemsContent_Loaded(object sender, RoutedEventArgs e)
        {
            GenerateContent(ItemsPanel, ItemTemplate, ItemsSource);
        }
    
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }
    
        public DataTemplate ItemTemplate
        {
            get { return (DataTemplate)GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); }
        }
    
        public DataTemplate ItemsPanel
        {
            get { return (DataTemplate)GetValue(ItemsPanelProperty); }
            set { SetValue(ItemsPanelProperty, value); }
        }
    
        private void GenerateContent(DataTemplate itemsPanel, DataTemplate itemTemplate, IEnumerable itemsSource)
        {
            Blocks.Clear();
            if (itemTemplate != null && itemsSource != null)
            {
                FrameworkContentElement panel = null;
    
                foreach (object data in itemsSource)
                {
                    if (panel == null)
                    {
                        if (itemsPanel == null)
                            panel = this;
                        else
                        {
                            FrameworkContentElement p = Helpers.LoadDataTemplate(itemsPanel);
                            if (!(p is Block))
                                throw new Exception("ItemsPanel must be a block element");
                            Blocks.Add((Block)p);
                            panel = Attached.GetItemsHost(p);
                            if (panel == null)
                                throw new Exception("ItemsHost not found. Did you forget to specify Attached.IsItemsHost?");                            
                        }
                    }
                    FrameworkContentElement element = Helpers.LoadDataTemplate(itemTemplate);
                    element.DataContext = data;
                    Helpers.UnFixupDataContext(element);
                    if (panel is Section)
                        ((Section)panel).Blocks.Add(Helpers.ConvertToBlock(data, element));
                    else if (panel is TableRowGroup)
                        ((TableRowGroup)panel).Rows.Add((TableRow)element);
                    else if (panel is Paragraph && element is Inline)
                        ((Paragraph)panel).Inlines.Add((Inline)element);
                    else
                        throw new Exception(String.Format("Don't know how to add an instance of {0} to an instance of {1}", element.GetType(), panel.GetType()));
                }
            }
        }
    
        private void GenerateContent()
        {
            GenerateContent(ItemsPanel, ItemTemplate, ItemsSource);
        }
    
        private void OnItemsSourceChanged(IEnumerable newValue)
        {
            if (IsLoaded)
                GenerateContent(ItemsPanel, ItemTemplate, newValue);
        }
    
        private void OnItemTemplateChanged(DataTemplate newValue)
        {
            if (IsLoaded)
                GenerateContent(ItemsPanel, newValue, ItemsSource);
        }
    
        private void OnItemsPanelChanged(DataTemplate newValue)
        {
            if (IsLoaded)
                GenerateContent(newValue, ItemTemplate, ItemsSource);
        }
    
        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ItemsContent)d).OnItemsSourceChanged((IEnumerable)e.NewValue);
        }
    
        private static void OnItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ItemsContent)d).OnItemTemplateChanged((DataTemplate)e.NewValue);
        }
    
        private static void OnItemsPanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ItemsContent)d).OnItemsPanelChanged((DataTemplate)e.NewValue);
        }
    }
    
  • 静态辅助方法:

    internal static class Helpers
    {
        /// <summary>
        /// If you use a bindable flow document element more than once, you may encounter a "Collection was modified" exception.
        /// The error occurs when the binding is updated because of a change to an inherited dependency property. The most common scenario 
        /// is when the inherited DataContext changes. It appears that an inherited properly like DataContext is propagated to its descendants. 
        /// When the enumeration of descendants gets to a BindableXXX, the dependency properties of that element change according to the new 
        /// DataContext, which change the (non-dependency) properties. However, for some reason, changing the flow content invalidates the 
        /// enumeration and raises an exception. 
        /// To work around this, one can either DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=FrameworkElement}}" 
        /// in code. This is clumsy, so every derived type calls this function instead (which performs the same thing).
        /// See http://code.logos.com/blog/2008/01/data_binding_in_a_flowdocument.html
        /// </summary>
        /// <param name="element"></param>
        public static void FixupDataContext(FrameworkContentElement element)
        {
            Binding b = new Binding(FrameworkContentElement.DataContextProperty.Name);
            // another approach (if this one has problems) is to bind to an ancestor by ElementName
            b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(FrameworkElement), 1);
            element.SetBinding(FrameworkContentElement.DataContextProperty, b);
        }
    
    
        private static bool InternalUnFixupDataContext(DependencyObject dp)
        {
            // only consider those elements for which we've called FixupDataContext(): they all belong to this namespace
            if (dp is FrameworkContentElement && dp.GetType().Namespace == typeof(Helpers).Namespace)
            {
                Binding binding = BindingOperations.GetBinding(dp, FrameworkContentElement.DataContextProperty);
                if (binding != null
                    && binding.Path != null && binding.Path.Path == FrameworkContentElement.DataContextProperty.Name
                    && binding.RelativeSource != null && binding.RelativeSource.Mode == RelativeSourceMode.FindAncestor && binding.RelativeSource.AncestorType == typeof(FrameworkElement) && binding.RelativeSource.AncestorLevel == 1)
                {
                    BindingOperations.ClearBinding(dp, FrameworkContentElement.DataContextProperty);
                    return true;
                }
            }
            // as soon as we have disconnected a binding, return. Don't continue the enumeration, since the collection may have changed
            foreach (object child in LogicalTreeHelper.GetChildren(dp))
                if (child is DependencyObject)
                    if (InternalUnFixupDataContext((DependencyObject)child))
                        return true;
            return false;
        }
    
    
        public static void UnFixupDataContext(DependencyObject dp)
        {
            while (InternalUnFixupDataContext(dp))
                ;
        }
    
    
        /// <summary>
        /// Convert "data" to a flow document block object. If data is already a block, the return value is data recast.
        /// </summary>
        /// <param name="dataContext">only used when bindable content needs to be created</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Block ConvertToBlock(object dataContext, object data)
        {
            if (data is Block)
                return (Block)data;
            else if (data is Inline)
                return new Paragraph((Inline)data);
            else if (data is BindingBase)
            {
                BindableRun run = new BindableRun();
                if (dataContext is BindingBase)
                    run.SetBinding(BindableRun.DataContextProperty, (BindingBase)dataContext);
                else
                    run.DataContext = dataContext;
                run.SetBinding(BindableRun.BoundTextProperty, (BindingBase)data);
                return new Paragraph(run);
            }
            else
            {
                Run run = new Run();
                run.Text = (data == null) ? String.Empty : data.ToString();
                return new Paragraph(run);
            }
        }
    
    
        public static FrameworkContentElement LoadDataTemplate(DataTemplate dataTemplate)
        {
            object content = dataTemplate.LoadContent();
            if (content is Fragment)
                return (FrameworkContentElement)((Fragment)content).Content;
            else if (content is TextBlock)
            {
                InlineCollection inlines = ((TextBlock)content).Inlines;
                if (inlines.Count == 1)
                    return inlines.FirstInline;
                else
                {
                    Paragraph paragraph = new Paragraph();
                    // we can't use an enumerator, since adding an inline removes it from its collection
                    while (inlines.FirstInline != null)
                        paragraph.Inlines.Add(inlines.FirstInline);
                    return paragraph;
                }
            }
            else
                throw new Exception("Data template needs to contain a <Fragment> or <TextBlock>");
        }
    }
    
    内部静态类帮助程序
    {
    /// 
    ///如果多次使用可绑定流文档元素,则可能会遇到“Collection was modified”异常。
    ///由于对继承的依赖项属性的更改而更新绑定时会发生错误
    ///当继承的DataContext发生更改时。似乎继承的与DataContext完全相似的数据已传播到其子代。
    ///当子体的枚举到达BindableXXX时,该元素的依赖属性将根据新的
    ///DataContext,它更改(非依赖性)属性。但是,由于某些原因,更改流内容会使
    ///枚举并引发异常。
    ///要解决此问题,可以选择DataContext=“{Binding DataContext,RelativeSource={RelativeSource AncestorType=FrameworkElement}}”
    ///这很笨拙,所以每个派生类型都调用这个函数(执行相同的操作)。
    ///看http://code.logos.com/blog/2008/01/data_binding_in_a_flowdocument.html
    /// 
    /// 
    公共静态void fixUpdateContext(FrameworkContentElement)
    {
    绑定b=新绑定(FrameworkContentElement.DataContextProperty.Name);
    //另一种方法(如果这个方法有问题的话)是通过ElementName绑定到祖先
    b、 RelativeSource=新的RelativeSource(RelativeSourceMode.FindAncestor,类型为(FrameworkElement),1);
    SetBinding(FrameworkContentElement.DataContextProperty,b);
    }
    私有静态bool InternalUnfXupDataContext(DependencyObject dp)
    {
    /只考虑那些我们称为FixUpDATAcObjt()的元素:它们都属于这个命名空间。
    if(dp是FrameworkContentElement&&dp.GetType().Namespace==typeof(Helpers.Namespace)
    {
    Binding Binding=BindingOperations.GetBinding(dp,FrameworkContentElement.DataContextProperty);
    if(绑定!=null
    &&binding.Path!=null&&binding.Path.Path==FrameworkContentElement.DataContextProperty.Name
    &&binding.RelativeSource!=null&&binding.RelativeSource.Mode==RelativeSourceMode.FindAncestor&&binding.RelativeSource.AncestorType==类型化(FrameworkElement)&&binding.RelativeSource.AncestorLevel==1)
    {
    BindingOperations.ClearBinding(dp,FrameworkContentElement.DataContextProperty);
    返回true;
    }
    }
    //一旦我们断开绑定,返回。不要继续枚举,因为集合可能已更改
    foreach(对象)
    
    internal static class Helpers
    {
        /// <summary>
        /// If you use a bindable flow document element more than once, you may encounter a "Collection was modified" exception.
        /// The error occurs when the binding is updated because of a change to an inherited dependency property. The most common scenario 
        /// is when the inherited DataContext changes. It appears that an inherited properly like DataContext is propagated to its descendants. 
        /// When the enumeration of descendants gets to a BindableXXX, the dependency properties of that element change according to the new 
        /// DataContext, which change the (non-dependency) properties. However, for some reason, changing the flow content invalidates the 
        /// enumeration and raises an exception. 
        /// To work around this, one can either DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=FrameworkElement}}" 
        /// in code. This is clumsy, so every derived type calls this function instead (which performs the same thing).
        /// See http://code.logos.com/blog/2008/01/data_binding_in_a_flowdocument.html
        /// </summary>
        /// <param name="element"></param>
        public static void FixupDataContext(FrameworkContentElement element)
        {
            Binding b = new Binding(FrameworkContentElement.DataContextProperty.Name);
            // another approach (if this one has problems) is to bind to an ancestor by ElementName
            b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(FrameworkElement), 1);
            element.SetBinding(FrameworkContentElement.DataContextProperty, b);
        }
    
    
        private static bool InternalUnFixupDataContext(DependencyObject dp)
        {
            // only consider those elements for which we've called FixupDataContext(): they all belong to this namespace
            if (dp is FrameworkContentElement && dp.GetType().Namespace == typeof(Helpers).Namespace)
            {
                Binding binding = BindingOperations.GetBinding(dp, FrameworkContentElement.DataContextProperty);
                if (binding != null
                    && binding.Path != null && binding.Path.Path == FrameworkContentElement.DataContextProperty.Name
                    && binding.RelativeSource != null && binding.RelativeSource.Mode == RelativeSourceMode.FindAncestor && binding.RelativeSource.AncestorType == typeof(FrameworkElement) && binding.RelativeSource.AncestorLevel == 1)
                {
                    BindingOperations.ClearBinding(dp, FrameworkContentElement.DataContextProperty);
                    return true;
                }
            }
            // as soon as we have disconnected a binding, return. Don't continue the enumeration, since the collection may have changed
            foreach (object child in LogicalTreeHelper.GetChildren(dp))
                if (child is DependencyObject)
                    if (InternalUnFixupDataContext((DependencyObject)child))
                        return true;
            return false;
        }
    
    
        public static void UnFixupDataContext(DependencyObject dp)
        {
            while (InternalUnFixupDataContext(dp))
                ;
        }
    
    
        /// <summary>
        /// Convert "data" to a flow document block object. If data is already a block, the return value is data recast.
        /// </summary>
        /// <param name="dataContext">only used when bindable content needs to be created</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Block ConvertToBlock(object dataContext, object data)
        {
            if (data is Block)
                return (Block)data;
            else if (data is Inline)
                return new Paragraph((Inline)data);
            else if (data is BindingBase)
            {
                BindableRun run = new BindableRun();
                if (dataContext is BindingBase)
                    run.SetBinding(BindableRun.DataContextProperty, (BindingBase)dataContext);
                else
                    run.DataContext = dataContext;
                run.SetBinding(BindableRun.BoundTextProperty, (BindingBase)data);
                return new Paragraph(run);
            }
            else
            {
                Run run = new Run();
                run.Text = (data == null) ? String.Empty : data.ToString();
                return new Paragraph(run);
            }
        }
    
    
        public static FrameworkContentElement LoadDataTemplate(DataTemplate dataTemplate)
        {
            object content = dataTemplate.LoadContent();
            if (content is Fragment)
                return (FrameworkContentElement)((Fragment)content).Content;
            else if (content is TextBlock)
            {
                InlineCollection inlines = ((TextBlock)content).Inlines;
                if (inlines.Count == 1)
                    return inlines.FirstInline;
                else
                {
                    Paragraph paragraph = new Paragraph();
                    // we can't use an enumerator, since adding an inline removes it from its collection
                    while (inlines.FirstInline != null)
                        paragraph.Inlines.Add(inlines.FirstInline);
                    return paragraph;
                }
            }
            else
                throw new Exception("Data template needs to contain a <Fragment> or <TextBlock>");
        }
    }