Search code examples
wpfdatatemplateflowdocument

WPF DataTemplate get Flowdocument


I have two DataTemplate for my EvenementViewModel, one for read only (LectureEvenement) and the second for write (EditeurEvenement). The template is selected depending of the EvenementViewModel state. These template are used within a TabControl.

From the code behind (Button click), I would like to get the FlowDocument that is in the read only DataTemplate. The goal is to print the FlowDocument.

I need help to get the handle on the FlowDocument that is in the selected tab of the TabControl.

Any suggestion?

There is some part of the XAML code.

<Window.Resources>
    <DataTemplate x:Key="EditeurEvenement" DataType="{x:Type local:EvenementViewModel}">
        <ScrollViewer Name="Conteneur" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <StackPanel MaxWidth="1000">
                <Border BorderThickness="5" BorderBrush="#55CDD7E1">
                    <StackPanel Background="#55CDD7E1">
                        <!-- Centrale -->
                        <StackPanel DockPanel.Dock="Top" Margin="0,0,0,5" HorizontalAlignment="Left">
                            <TextBlock VerticalAlignment="Center"><Run Text="Centrale :" FontWeight="Bold"/></TextBlock>
                            <ComboBox MinWidth="160" ItemsSource="{Binding ListeCentrale}" DisplayMemberPath="Nom" SelectedItem="{Binding Centrale}"/>
                        </StackPanel>
...
                        </StackPanel>
                </Border>
            </StackPanel>
        </ScrollViewer>
    </DataTemplate>

    <DataTemplate x:Key="LectureEvenement" DataType="{x:Type local:EvenementViewModel}">
        <FlowDocumentScrollViewer VerticalScrollBarVisibility="Auto">
            <FlowDocument FontFamily="Sergoe UI" FontSize="12px" Name="FdEvenement">
                <Paragraph>
                    <!-- Centrale -->
                    <TextBlock Margin="0,0,0,5"><Run Text="Centrale : " FontWeight="Bold"/><Run Text="{Binding Centrale.Nom, Mode=OneWay}"/></TextBlock>
                    <LineBreak/>
...
                </Paragraph>
            </FlowDocument>
        </FlowDocumentScrollViewer>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:EvenementViewModel}">
        <ContentControl Content="{Binding}">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate" Value="{StaticResource LectureEvenement}"></Setter>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding EstModifiable}" Value="True">
                            <Setter Property="ContentTemplate" Value="{StaticResource EditeurEvenement}"></Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </DataTemplate>
</Window.Resources>

    <TabControl x:Name="TcEvenements" ItemsSource="{Binding ListeOngletOuvert}" SelectedItem="{Binding OngletSelectionne}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding TitreTab}" Margin="0,0,5,0" VerticalAlignment="Center"/>
                    <Button CommandParameter="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Command="{Binding LancerFermer}">
                        <Image Source="Icone/icons8-delete-23.png" Width="15"/>
                    </Button>
                </StackPanel>
            </DataTemplate>
        </TabControl.ItemTemplate>
    </TabControl>

Solution

  • The FlowDocumentScrollViewer element is a visual child of the TabControl whenever your template is applied. You can then get a reference to it using the VisualTreeHelper class:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        FlowDocumentScrollViewer fdsv = FindVisualChild<FlowDocumentScrollViewer>(TcEvenements);
        if (fdsv != null)
        {
            FlowDocument fd = fdsv.Document;
            //...
        }
    }
    
    private T FindVisualChild<T>(Visual visual) where T : Visual
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
        {
            Visual child = (Visual)VisualTreeHelper.GetChild(visual, i);
            if (child != null)
            {
                T correctlyTyped = child as T;
                if (correctlyTyped != null)
                {
                    return correctlyTyped;
                }
    
                T descendent = FindVisualChild<T>(child);
                if (descendent != null)
                {
                    return descendent;
                }
            }
        }
    
        return null;
    }