私の 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()
します。どちらも現在のオブジェクトの子ではありませんでした。printContentControl
content
- またはが`{x:Null}' の
DataTrigger
場合、XAML で s を使用してテンプレートを置き換えます。無効。Content
DataContext
ContentControl
印刷コマンドを実行すると が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); })); }