Print Footer issues

Hello Walter,

I have trouble getting the print footer to work properly with several issues I can’t resolve.

1. Data Binding
I followed the printing part of your introduction document but I can’t get the binding to work.

Xaml:

<DataTemplate x:Key="PrintTemplate">
  <go:SpotPanel>
    <Grid go:SpotPanel.Spot="MiddleBottom"
          go:SpotPanel.Alignment="MiddleTop">
      ...
      <TextBlock Margin="10 0"
                 FontWeight="SemiBold"
                 Text="{Binding Path=PrintData.CompanyName, Mode=TwoWay}"/>
      ...
    </Grid>
  </go:SpotPanel>
</DataTemplate>

<go:Diagram ... >
  ...
  <go:Diagram.PrintManager>
    <go:PrintManager Scale="NaN"
                     ForegroundTemplate="{StaticResource PrintTemplate}"
                     PageOptions="Full"
                     Margin="15 15 15 60"/>
  </go:Diagram.PrintManager>
</go:Diagram>

View model (the actual view model is a decendant of this one)

public abstract class AstaViewModel : NavigationAwareViewModelBase, IRegionMemberLifetime {
    private PrintData _printData;
    public PrintData PrintData {
        get { return this._printData }
        set { SetProperty(ref _printData, value); }
    }
    ...
}

Print data

public class PrintData : INotifyPropertyChanged {
    private string _companyName;
    public string CompanyName {
        get { return this._companyName }
        set { 
            if (this._companyName.Equals(value)) { return; }
            this._companyName = value;
            OnPropertyChanged();
        }
    }
}

What am I doing wrong? I had issues with data binding in DataTemplates in the past where I had to set the binding source. Might this be an issue here, too? Can’t see anything about that in the introduction document though.

2. Horizontal alignment
I actually have two elements in my footer, which are supposed to be aligned one on the left and the other on the right, so the footer stretches across the whole page. It doesn’t. It’s always centered and only takes up as much space as the content requires.

 <DataTemplate x:Key="PrintTemplate">
   <go:SpotPanel HorizontalAlignment="Stretch">
     <Grid go:SpotPanel.Spot="MiddleBottom"
           go:SpotPanel.Alignment="MiddleTop">
       <Grid.ColumnDefinitions>
         <ColumnDefinition Width="Auto"></ColumnDefinition>
         <ColumnDefinition Width="*"></ColumnDefinition>
         <ColumnDefinition Width="Auto"></ColumnDefinition>
       </Grid.ColumnDefinitions>
       <Grid.RowDefinitions>
         <RowDefinition></RowDefinition>
         <RowDefinition></RowDefinition>
       </Grid.RowDefinitions>
                    
       <TextBlock Margin="10 0 10 5" 
                  FontSize="11"
                  Grid.ColumnSpan="3"
                  Text="{x:Static trans:Resources.ComponentsTab_PrintCaption}">
       </TextBlock>

       <UniformGrid Rows="6" Columns="3"
                    Grid.Column="0" Grid.Row="1">
         ...
       </UniformGrid>
       <StackPanel Grid.Column="2" Grid.Row="1">
         ...
       </StackPanel>
     </Grid>
   </go:SpotPanel>
 </DataTemplate>

It’s bound to a PageInfo, so that the example bindings work:
<TextBlock Text="{Binding Row}" />

But you can get to what you want via:
<TextBlock Text="{Binding Diagram.Model.PrintData.CompanyName}" />

I hope I got that property path right for your setup. You may need to fiddle with it.

I don’t think I quite understand. The properties to bind for printing have to be part of the GraphLinksModel that is assigned to the Diagram’s model?

I assumed from your description that Diagram.Model is an instance of AstaViewModel. If that’s not the case, you can adapt the binding to fit your environment.

No, we are actually using Prism with MVVM for WPF with AstaViewModel being the view model, that is, it is a decendant of BindableBase, the view bound prism class.

This AstaViewModel contains a Diagram property to which the Diagram in the Xaml code is bound to. And that Diagram’s Model is an object of class AstaData.

I will try to outsource the PrintData into the AstaData class and see whether this solves the problem.

Alright, after moving the PrintData to the AstaData class and using the Diagram.Model. prefix in the binding it finally worked. Thanks.

What about the other problem with the footer not taking up the whole page width?

Don’t you need to set HorizontalAlignment=“Stretch” on the Grid itself?

Already tried that but didn’t work.

Ah, because a SpotPanel doesn’t observe that property.

I wonder if you could use a Grid instead of a SpotPanel and bind its width and height to the PageInfo.Viewport.

If I replace the SpotPanel with a Grid the SpotPanel.Spot and SpotPanel.Alignment won’t work anymore. The footer gets drawn into the upper left corner of the page right onto the diagram.

Can’t I set the SpotPanel’s width? How would I do the binding? Setting Width="{Binding Path=PageInfo.Viewport}" doesn’t do anything, neither on a grid nor on the SpotPanel, so I wonder if this is correct.

Forget about GoXam and just implement some XAML that does what you want, except that the overall height and width of the Grid is determined by the PageInfo.Viewport.

Well, as said, I don’t know how to go on about that. How do I bind to the PageInfo? This doesn’t work:

<DataTemplate x:Key="PrintTemplate">
  <Grid Height="{Binding Path=PageInfo.Viewport.Height}"
        Width="{Binding Path=PageInfo.Viewport.Width}"
        Background="#883484b3">

    <TextBlock Margin="10 10 10 5" 
               FontSize="11"
               Text="{x:Static trans:Resources.ComponentsTab_PrintCaption}"/>
    </TextBlock>
  </Grid>
</DataTemplate>

I’ve noticed that the PageInfo class is a sealed class inside the PrintManager but there is no property.

Try removing “PageInfo.” from your binding property path – it’s data bound to a PageInfo, not to something that has a “PageInfo” property.

Alright, I got it to work, thanks.

One more thing, though. The diagram itself is always placed in the top left corner. Is there a way to center it?

Good.

I don’t know about automatically centering. Would you only want to do that if everything fit on one page, not if it requires multiple pages?

I suppose you could calculate whether the bounds would fit within the page, and if so, you could increase the Margin accordingly. You’ll need to experiment to see if that might work.

I’ve set the page option of the PrintManager to full, so it always gets printed on a single page.

The “Full…” PageOptions choices control whether to occupy the whole page of the last row and last column of pages. That includes when there’s only one page to print.

Setting the PrintManager.Scale to NaN or zero causes printing to automatically scale everything to fit in one page.

Uh … right. I did both, though. But there is no way around fiddling with the margins manually?

I was guessing that computing the PrintManager.Margin was easiest.

An alternative would be to artificially increase the Diagram.Panel.Padding temporarily during the printing operation.

I guess you would only need to increase the Thickness on the Left and on the Top. That applies to both techniques.

I’ve written a function that calculates the proper top or left margin now, but how do I get the page size?