[英]Use of ItemsControl ActualHeight to paginate a printed XAML form?
我需要使用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;
初始Measure / Arrange 確實為我提供了maxRowsHeight的期望值。 並且生成的表單對於帶有幾行的單個頁面看起來不錯。 我的具體問題是: 為什么page._rowsControl.ActualHeight始終為零 ? 通常,是否有更好的方法來解決此問題?
這是一個解決方案。 我們正在嘗試將視圖關注點與視圖模型關注點分開,因此仍然有待改進。
報表類中的CreatePages方法現在為:
private static IEnumerable<XAML_Form> CreatePages()
{
IList<XAML_Form> pages = new List<XAML_Form>();
int rowCount = sourceRowsObjectList.Count;
int remainingRowCount = rowCount;
do
{
var pageVm = new PageViewModelClass();
var page = new XAML_Form(pageVm);
pages.Add(page);
int numberOfRowsToAdd = Math.Min(remainingRowCount, XAML_Form.MaxNumberOfRows);
pageVm.AddRows(sourceRowsObjectList.Skip(rowCount - remainingRowCount).Take(numberOfRowsToAdd));
remainingRowCount -= numberOfRowsToAdd;
while (page.AreRowsOverflowing())
{
pageVm.RemoveLastRow();
remainingRowCount++;
}
} while (remainingRowCount > 0);
return pages;
}
后面的相關XAML_Form代碼如下:
private static int _maxNumberOfRows = -1;
public XAML_Form(PageViewModelClass viewModel)
{
InitializeComponent();
Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
Arrange(new Rect(new Point(0, 0), DesiredSize);
ViewModel = viewModel;
}
public PageViewModelClass ViewModel
{
get { return (PageViewModelClass)DataContext; }
private set { DataContext = value; }
}
public static int MaxNumberOfRows
{
get // Compute this only once, the first time it is called.
{
if (_maxNumberOfRows < 0) return _maxNumberOfRows;
var page = new XAML_Form();
var singleRowCollection = new object[] { null; }
page._rowsControl.ItemsSource = singleItemCollection;
page._rowsControl.UpdateLayout();
var rowHeight = page._rowsControl.ActualHeight;
_maxNumberOfRows = (int)((page.DesiredSize.Height - page._headerControl.ActualHeight) / rowHeight);
page._rowsControl.ItemsSource = null;
return _maxNumberOfRows;
}
}
// Call this method as rarely as possible. UpdateLayout is EXPENSIVE!
public bool AreRowsOverflowing()
{
_rowsControl.UpdateLayout();
return _rowsControl.ActualHeight > DesiredSize.Height - _headerControl.ActualHeight;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.