【发布时间】:2013-01-09 16:23:41
【问题描述】:
我需要使用 XAML 生成一个打印表单,该表单具有一个标题网格和可变数量的行,随着行数的增加可能会产生多个页面。标题必须出现在每一页上,并且由于行内的文本换行,每一行的高度可能会有所不同。我目前正在尝试使用 ItemsControl(行容器)的 ActualHeight 来确定何时生成新页面,但 ActualHeight 的值始终为零强>。
我的“XAML_Form”具有以下结构。在 ItemTemplate 中使用了一个网格,以允许将行中的列与标题网格中的列对齐。
<Grid Width="980" Height="757">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Name="_headerControl" Grid.Row="0"/>
<ItemsControl Name=_rowsControl ItemsSource={Binding Rows} Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
我们的架构有一个报告类,用于处理添加页脚、页码以及将页面聚合到 PDF 中。此报表类对每个 XAML 视图页面都有一个嵌套的 ViewModel。每个页面的 ViewModel 使用行对象的后备列表:
List<RowClass> RowsList;
ViewModel 还有一个 ICollectionView 用于绑定为 ItemsSource:
ICollectionView Rows = new ListCollectionView(RowsList);
我的报表类有一个 CreatePages 方法,其中包含如下代码:
IList<XAML_Form> pages = new List<XAML_Form>();
var vm = new PageViewModelClass();
var page = new XAML_Form { DataContext = vm };
page.InitializeComponent();
page.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity);
page.Arrange(new Rect(new Point(0,0), page.DesiredSize));
var maxRowsHeight = page.DesiredSize.Height - page._headerControl.ActualHeight;
pages.Add(page);
var rowsOnPage = 0;
foreach (var row in sourceRowsObjectList)
{
rowsOnPage++;
vm.RowsList.Add(row);
vm.Rows.Refresh();
page.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity);
page.Arrange(new Rect(new Point(0,0), page.DesiredSize));
if (page._rowsControl.ActualHeight <= maxRowsHeight)
continue;
// The rows exceed the available space; the row needs to go on the next page.
vm.RowsList.RemoveAt(--rowsOnPage);
vm = new PageViewModelClass();
vm.RowsList.Add(row);
rowsOnPage = 1;
page = new XAML_Form { DataContext = vm };
page.InitializeComponent();
pages.Add(page);
}
return pages;
初始测量/排列确实为我提供了 maxRowsHeight 的预期值。生成的表单对于有几行的单个页面看起来很好。我的具体问题是:为什么 page._rowsControl.ActualHeight 总是为零?一般来说,有没有更好的方法来解决这个问题?
【问题讨论】:
-
我通过 WPF 博士的系列深入研究了 ItemsControl。我看到“网格”不是项目控制类的项目宿主之一。这和这个有关系吗?
-
终于在这方面取得了一点进展。可以调用“非常不鼓励”的 UpdateLayout 方法。由于这太贵了,我不想在添加每一行后调用 UpdateLayout。相反,我将添加应该适合页面而不换行的行数,然后调用 UpdateLayout。如果它们不适合,则继续删除一行并调用 UpdateLayout,直到行适合。仍然没有对这种方法感到欣喜若狂,但看起来它会奏效。
标签: wpf xaml itemscontrol measure actualheight