如何测量从分层数据模板创建的UIElement

时间:2014-12-21 15:50:49

标签: silverlight printing datatemplate measure

伙计们,我即将从Silverlight 5打印一个分层数据。我使用资源字典来定义数据的布局。像这样的主要xaml段:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:MSCE.SL.ArchievementAssessment"
                    xmlns:stat="clr-namespace:MSCE.SL.ArchievementAssessment.Statistics">
    <DataTemplate DataType="stat:Level1">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Name}" VerticalAlignment="Center"/>
            <ItemsControl Grid.Column="1" ItemsSource="{Binding Children}"/>
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="stat:Level2">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Name}" VerticalAlignment="Center"/>
            <ItemsControl Grid.Column="1" ItemsSource="{Binding Children}"/>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="Level3ItemTemplate">
         ....
    </DataTemplate>
    <DataTemplate DataType="stat:Level3">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Name}" VerticalAlignment="Center"/>
            <ListBox Grid.Column="1" ItemsSource="{Binding Children}"
                     ItemTemplate="{StaticResource Level3ItemTemplate}"/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

然后我在打印代码中使用这些模板如下:

  void Print(object para)
  {
      PrintDocument pd = new PrintDocument();
      List<FrameworkElement> pages = null;
      int pageIndex = 0;

      pd.PrintPage += (s, e) =>
      {
          if (pages == null)
          {
              pages = CreatePages(e.PrintableArea);
          }
          e.PageVisual =  pages[pageIndex] ;
          pageIndex++;
          e.HasMorePages = pageIndex < pages.Count;
      };
      pd.Print("statistics");
}
    List<FrameworkElement> CreatePages(Size printableArea)
    {
        // create result pages' container
        List<FrameworkElement> pages=new List<FrameworkElement>();

        // get resources for printing
        IEnumerable<Level1> data=...// detail ignored, get data from ViewModel
        ResourceDictionary res=...  // detail ignored, get data template from assembly  

        // create page root visual and 
        // merge printing templates' resource into root's resource dictionary  
        StackPanel root=new StackPanel();
        root.ResourceDictionary.MergedDictionaries.Add(res); 

        // fetch data template of data Level1
        var level1Template=root.Resources[new DataTemplateKey(typeof(Level1))] as DataTemplate;

        // trace height of available space 
        double availableContentHeight=printableArea.Height;

        foreach(var lvl1 in data)
        {
            // create UI of Level1 using template 
            var ui=level1Template.LoadContent() as FrameworkElement;
            ui.DataContext = data;
            ui.OnApplyTemplate();

            // measure the size requirement of this Level1's UI
            ui.Measure(printableArea);

            // if available space is not enough, add the last page to pages container
            // and create a new page to contain new created Level1 UI
            if(ui.DesireSize.Height>availableContentHeight)
            {
                pages.Add(root);
                root=new StackPanel();
                availableContentHeight=printableArea.Height;
            }
            root.Children.Add(ui);
            availableContentHeight-=ui.DesiredSize.Height;
        }
        pages.Add(root);
        return pages;
    }

问题出现在测量。它应该包含大约三页。但基于测量结果的所有Level1 UI的高度总和仅占用半页。因此,打印机始终只打印一页并减少许多内容。我认为Level1 UI的Measure方法只返回其标题的高度(TextBlock Text =“{Binding Name}”),它不包括level1的子节点的空间要求,当然还包括level2的子节点的空间要求。

一开始,我没有把语句 ui.OnApplyTemplate()。问题发生后,我认为这可能会预先加载所有儿童内容,我可以得到正确的测量结果。但实际上它什么都没改变。

现在,我的想法是,在将数据Level1的整个可视化树添加到PringPageEventArgs的PageVisual以获得正确的测量结果之前预先加载,或者编写一个层次化的测量方法来测量从底部(level3的子项)到顶部的Level1 UI 。

因为我的实际数据模板比上面的模板更复杂,所以第二种方法是时间推移并且容易引入错误。所以我希望有人教我如何完成第一条道路或指导我找到明确的解决方案。

1 个答案:

答案 0 :(得分:0)

好吧,过了几天,我不得不用近似算法处理测量问题。我假设每个详细的level3行只占用一行,然后测量每行的高度并将所有高度值相加。没有累积测量,不完美,但它可以应付案例。