Joh*_*Doh 6 c# wpf wpf-controls visual-studio wpf-4.0
我们有一个相当大的WPF业务应用程序,我正在研究现有的WPF FixedPage/FixedDocument报告的重组.
这是一个有点繁忙的生态系统.我们有一个内置的表单生成器,你可以使用许多不同的控件(就像一个迷你内置的可视化工作室).一切正常.您在屏幕上填写表格,然后您可以打印(到XPS)相同的副本到标准8.5x11纸张.
在代码中,我们将此报告分解为垂直块.假设每张纸块在打印的纸上都是一英寸或两英寸高.这就是我们处理分页的方式.如果下一个块对于页面太高,我们执行NewPage()并重复.正如我所提到的,这很好.
WPF有一个巨大的学习曲线,我一直在回顾旧代码和重构事物,并愉快地使用DataTemplates,强类型ViewModels和通用ContentControls来减少代码的大小.屏幕上的表单生成器仍然有效,但FixedDocument报告已经变得奇怪了.
回到那些垂直切片,我们将用户的表单打印为纸张作为单独的网格控件.没有什么花哨.每个网格(如上所述)可能是一英寸或两英寸高,包含复选框,单选按钮,文本块等的任意随机混合.
当网格包含这些库存(标准)MS WPF控件时,我可以整天这样做:
System.Windows.Controls.Grid g = .....
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
Run Code Online (Sandbox Code Playgroud)
并获得适当的尺寸,即100 x 67.
现在,有时网格只有一个控件 - 如果你愿意的话就是一个标题(即"本月的时间表").添加到该网格的唯一子控件是ContentControl.
ContentControl只是绑定到ViewModel:
<ContentControl Content="{Binding}" />
Run Code Online (Sandbox Code Playgroud)
然后在资源字典中有两个DataTemplates来获取这个绑定.在这里,我将展示:
<UserControl.Resources>
<w:MarginConverter x:Key="boilerMargin" />
<DataTemplate DataType="{x:Type render:BoilerViewModel}">
<render:RtfViewer
Width="{Binding Path=Width}"
TextRTF="{Binding Path=Rtf}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type render:Qst2NodeViewModel}">
<ContentControl Content="{Binding Path=BoilerVm}">
<ContentControl.Margin>
<MultiBinding Converter="{StaticResource boilerMargin}">
<Binding Path="NodeCaptionVm.Height" />
<Binding Path="NodeLeft" />
</MultiBinding>
</ContentControl.Margin>
</ContentControl>
</DataTemplate>
</UserControl.Resources>
Run Code Online (Sandbox Code Playgroud)
ContentControl将获取最底部的datatemplate.然后该模板将使用上面较小的模板.
花式转换器只是设置了一个余量.阅读可能很难看,但这一切都在父用户控件的屏幕上正确显示.它的大小和理由都是正确的.
在打印报告方面(XPS),我必须在代码中创建这些控件并测量它们以查看它们是否适合当前的FixedPage.当我去做这一步时:(在包含此ContentControl的网格上)
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
Run Code Online (Sandbox Code Playgroud)
我回到0,0大小.即使它应该像730x27一样.再次,在屏幕上,托管在UserControl中,这一切都很好.只是尝试实例化它并纯粹在代码中测量它失败了.我已经确认控件已添加到网格中,其行和列集已添加到Children集合中,等等...
如果我使用UpdateLayout调用添加这两个语句,就像这样,那么它的工作原理如下:
g.UpdateLayout(); //this fixes it
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
Run Code Online (Sandbox Code Playgroud)
我一直在阅读UpdateLayout很昂贵而且要避免,在将其添加到FixedDocument报告的FixedPage之前,我宁愿不在每个网格部分调用它.可能有几十甚至几百次迭代.而且,再次,如果网格中有常规的WPF控件,没有任何ContentControls和花哨的查找和查找数据窗口,测量工作正常,没有UpdateLayout调用.
有什么建议?谢谢!
我只是不明白为什么有必要在我开始使用Xaml引擎后开始调用它.几乎感觉我因使用高级功能而受到惩罚.
很难解释,但让我尝试使用简单的单词...在wpf中,一切都与调度员一起工作.此外,您可能已经知道调度员处理按优先级排序的任务.
例如,首先控制正在初始化,然后触发绑定,然后更新值,最后测量所有正在测量等等.
你以某种方式管理的是通过在contentcontrol内部设置所有这些内容控件,你搞砸了那个订单
调用UpdateLayout基本上会强制调度程序在布局中完成其挂起的工作,以便您可以在之后使用干净的布局
使用调度程序进行拧紧在wpf中非常常见,因为某些控件或值可能会在以后添加,最终会重新测量.
在你的情况下,你似乎在一个方法调用中一次创建所有,而不让调度员喘口气.因此,您需要UpdateLayout方法来规范化调度程序队列.
我希望这可以帮助你.您还可以使用Dispatcher.BeginInvoke解决您的问题.
| 归档时间: |
|
| 查看次数: |
5768 次 |
| 最近记录: |