Как переместить элемент WPF UIElement из визуального дерева в FixedPage?

Мое приложение 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 к нулю (как в коде выше).
  • настройка this.Content=null, Экран гаснет, но все равно получаю исключение.
  • С помощью RemoveLogicalChild() на различных элементах управления. Ни один из которых не работал.
  • С помощью RemoveVisualChild() на printContentControl и content объект. Ни один из них не был дочерним объектом текущего объекта.
  • С помощью DataTriggers в XAML, чтобы заменить шаблон, когда Content или же DataContext из ContentControl is `{x:Null}'. Нет эффекта.

Неважно, если внешний вид экрана испортился, как ViewModel изменяет View когда его команда печати выполнена.

Как я могу переместить printContentControlВизуальный контент (или весь элемент управления) из ViewВизуальное дерево к ViewModel"s FixedPage объект?

Грязный обход

Создав класс-обертку для содержимого, которое нужно напечатать, я могу заставить функционал работать, но он не отвечает на первоначальный вопрос.

Класс Wrapper

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

0 ответов

Другие вопросы по тегам