我的 MVVM 应用程序使用屏幕上的视觉对象将屏幕内容渲染到打印文档。我的视图有一个ContentControl
使用DataTemplate
资源来确定要显示的内容,但是当我尝试将该内容添加到FixedPage
对象,我得到一个ArgumentException
带有消息:
指定的 Visual 已经是另一个 Visual 的子级或 CompositionTarget 的根。
处理打印的视图的(简化的)XAML 代码如下所示:
<DockPanel>
<!-- Print button -->
<Button DockPanel.Dock="Top"
DataContext="{Binding Path=PrintCommand}"
Click="PrintButton_Click" />
<!-- Print container. -->
<Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top" >
<!-- The visual content of this is what needs adding to the FixedPage. -->
<ContentControl x:Name="printContentControl"
Content="{Binding Path=PrintMe}" />
</Border>
</DockPanel>
...有问题的打印按钮单击处理程序背后的代码如下所示:
private void PrintButton_Click(object sender, RoutedEventArgs e)
{
// Get a reference to the Visual objects to be printed.
var content = VisualTreeHelper.GetChild(printContentControl, 0);
Debug.Assert((content as UIElement) != null, "Print content is not a UIElement");
#region This doesn't work. See below for other things that also don't work.
printContentControl.Content = null;
// The line below doesn't help, but tried it in case the framework
// needed a poke to get it to update the visual tree.
UpdateLayout();
#endregion
// Make sure that all the data binding, layout, etc. has completed
// before the visual object is printed by queuing the print job at
// a later priority.
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate()
{
// Create a fixed page to hold the content to print.
FixedPage page = new FixedPage();
// Add the content to print to the page.
#region Here be dragons: 'System.ArgumentException'
page.Children.Add(content as UIElement);
#endregion
// Send the document back to the View model for actual printing.
var command = ((sender as Button).DataContext as ICommand);
command.Execute(page);
}));
}
我尝试了以下方法来解决该问题,但均未成功:
- 设置
Content
的成员ContentControl
为 null(如上面的代码)。
- Setting
this.Content=null
。屏幕一片空白,但仍然出现异常。
- Using
RemoveLogicalChild()
在各种控制上。这些都不起作用。
- Using
RemoveVisualChild()
on the printContentControl
和content
目的。它们都不是当前对象的子对象。
- Using
DataTrigger
XAML 中的 s 来替换模板Content
or DataContext
of the ContentControl
是“{x:Null}”。没有效果。
屏幕的外观是否混乱并不重要,因为ViewModel
改变了View
当执行其打印命令时。
我怎样才能移动printContentControl
的视觉内容(或整个控件)来自View
的视觉树ViewModel
's FixedPage
object?
肮脏的解决方法
通过为要打印的内容创建一个包装类,我可以使该功能正常工作,但它并没有回答最初的问题。
包装类
public class PrintContentControl : UserControl
{
internal UIElement GetPrintContent()
{
UIElement printContent = Content as UIElement;
Content = null;
return printContent;
}
}
使用包装器更新了 XAML 来保存可打印内容
<Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top" >
<c:PrintContentControl x:Name="printContent">
<ContentControl ContentTemplate="{StaticResource ReportTemplate}"
Content="{Binding Path=PrintMe}" />
</c:PrintContentControl>
</Border>
更新了后面的代码以从包装器获取可打印内容
private void PrintButton_Click(object sender, RoutedEventArgs e)
{
// Use the wrapper to get the Visual objects to be printed.
UIElement content = printContent.GetPrintContent();
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(delegate()
{
// Works fine now.
FixedPage page = new FixedPage();
page.Children.Add(content as UIElement);
var command = ((sender as Button).DataContext as ICommand);
command.Execute(page);
}));
}