2

我的 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(如上面的代码中所示)。
  • 设置this.Content=null。屏幕变为空白,但仍然出现异常。
  • RemoveLogicalChild()在各种控件上使用。这些都没有奏效。
  • RemoveVisualChild()printContentControlcontent对象上使用。它们都不是当前对象的子对象。
  • 当或为“{x:Null}”时,在 XAML 中使用DataTriggers 替换模板。没有效果。ContentDataContextContentControl

屏幕外观是否混乱并不重要,因为执行打印命令时ViewModel会发生变化。View

如何将printContentControl' 的可视内容(或整个控件)从View' 的可视树移动到ViewModel' 的FixedPage对象?

肮脏的解决方法

通过为要打印的内容创建一个包装类,我可以使功能正常工作,但它不能回答原始问题。

包装类

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);
    }));
}
4

0 回答 0