GoXam Silverlight Printing Problem

Hi,

we have a silvelight printing problem, GoXam 1.3.5.5 with Silverlight 5.

If we print in silverlight over Printmanager.Print() result is an empty Sheet with something like that: 1,2 (1x1).

If we print in WPF (same code) over Printmanger.Print(PrintDialog) the result is as expected.

What can we do?

PrintManager-Code:

public class PreviewingPrintManager : PrintManager
{

    public PreviewingPrintManager(): base()
    {
        this.PageBackground = new SolidColorBrush(Colors.White);
    }


    public Brush Background { get; set; }

    // Setup this Diagram.PrintManager to automatically update the "Print Grid".
    public void Init(Diagram diagram)
    {
        diagram.PrintManager = this;
        if (diagram.Panel != null)
        {
            InitDiagram();
        }
        else
        {
            diagram.TemplateApplied += (sd, ev) =>
            {
                InitDiagram();
            };
        }
        this.Loaded += new RoutedEventHandler(PreviewingPrintManager_Loaded);
    }

    void PreviewingPrintManager_Loaded(object sender, RoutedEventArgs e)
    {
        this.UpdatePrintGrid();
    }

    private Point _Location =new Point(0,0);
    public Point Location { get { return this._Location; } set { this._Location = value; this.UpdatePrintGrid(); } }

    private void InitDiagram()
    {
        //if (!this.Inited)
        //{
            this.Inited = true;
            if (this.PrintableArea.Height ==0 || this.PrintableArea.Width==0)
            {

#if SILVERLIGHT
this.PrintableArea = new Size(816, 1056); //??? how to get default printer page information
#else
// get the default printer’s printable area
var dlg = new PrintDialog();
this.PrintableArea = new Size(dlg.PrintableAreaWidth, dlg.PrintableAreaHeight);
#endif
// automatically update the print grid’s position and size
//this.Diagram.Panel.DiagramBoundsChanged += (s, e) => UpdatePrintGrid();
}
UpdateAutoScales();
UpdateIsPrintPreviewEnabled();
//}
}
private bool Inited { get; set; }

    // Gets or sets whether the DiagramPanel.Scale determines the PrintManager.Scale,
    // or whether the user can change the DiagramPanel.Scale using control-shift-mouse-wheel.
    public bool AutoScales
    {
        get { return _AutoScales; }
        set
        {
            if (_AutoScales != value)
            {
                _AutoScales = value;
                UpdateAutoScales();
            }
        }
    }
    private bool _AutoScales;

    private void UpdateAutoScales()
    {
        Diagram diagram = this.Diagram;
        if (diagram == null) return;
        if (diagram.Panel == null) return;
        if (this.AutoScales)
        {
            // support having the print scale be the same as the DiagramPanel.Scale
            this.Diagram.Panel.ViewportBoundsChanged += HandleViewportBoundsChanged;
            if (this.Diagram.DefaultTool is PrintPreviewToolManager) this.Diagram.DefaultTool = new ToolManager();
        }
        else
        {
            // support control-shift-mouse-wheel changing only the print scale
            this.Diagram.Panel.ViewportBoundsChanged -= HandleViewportBoundsChanged;
            if (!(this.Diagram.DefaultTool is PrintPreviewToolManager)) this.Diagram.DefaultTool = new PrintPreviewToolManager();
        }
    }

    // Gets or sets whether the print-preview grid is visible
    public bool IsPreviewEnabled
    {
        get { return _IsPreviewEnabled; }
        set
        {
            if (_IsPreviewEnabled != value)
            {
                _IsPreviewEnabled = value;
                UpdateIsPrintPreviewEnabled();
            }
        }
    }
    private bool _IsPreviewEnabled;

    private void UpdateIsPrintPreviewEnabled()
    {
        Diagram diagram = this.Diagram;
        if (diagram == null) return;
        if (diagram.Panel == null) return;
        Node printGrid = diagram.PartsModel.FindNodeByKey("PrintGrid");
        if (printGrid != null)
        {
            printGrid.Visible = this.IsPreviewEnabled;
            UpdatePrintGrid();
        }
    }

    // The size of the printed area, inside the margins, in model coordinates;
    // set this to the selected printer's PrintableArea.
    // This is initialized to be the default printer's PrintableArea in WPF.
    // In Silverlight you must set this property.
    // In WPF you should set this whenever the user chooses a different printer.
    public Size PrintableArea
    {
        get { return _PrintableArea; }
        set
        {
            if (_PrintableArea != value &&
                !Double.IsInfinity(value.Width) && !Double.IsNaN(value.Width) &&
                !Double.IsInfinity(value.Height) && !Double.IsNaN(value.Height))
            {
                _PrintableArea = value;
                UpdatePrintGrid();
            }
        }
    }
    private Size _PrintableArea = new Size(0, 0);

    // If you change the PrintManager.Scale, call UpdatePrintGrid() afterwwards.

    private void HandleViewportBoundsChanged(object sender, EventArgs e)
    {
        if (!this.IsPreviewEnabled) return;
        Diagram diagram = this.Diagram;
        if (diagram == null) return;
        if (diagram.Panel == null) return;
        this.Scale = diagram.Panel.Scale;
        UpdatePrintGrid();
        
        
    }

    private Brush _Background = null;
    public Brush PageBackground { get { return this._Background; } set { this._Background = value; this.UpdatePrintGrid(); } }

#if SILVERLIGHT
private bool _LastIsPrintGridVisible;
protected override void DoPrint(System.Windows.Printing.PrintDocument pdoc)
{
try
{
pdoc.PrintPage += new EventHandler<System.Windows.Printing.PrintPageEventArgs>(pdoc_PrintPage);
this._LastIsPrintGridVisible = this.Diagram.GridVisible;
pdoc.EndPrint += new EventHandler<System.Windows.Printing.EndPrintEventArgs>(pdoc_EndPrint);
base.DoPrint(pdoc);
}
catch { }
}

    void pdoc_PrintPage(object sender, System.Windows.Printing.PrintPageEventArgs e)
    {
        //(e.PageVisual as Canvas).Children.RemoveAt(0);
        //(e.PageVisual as Canvas).Children.RemoveAt(0);
    }

    void pdoc_EndPrint(object sender, System.Windows.Printing.EndPrintEventArgs e)
    {
        this.Diagram.GridVisible = this._LastIsPrintGridVisible;
    }

#endif

    // Update the position and size and CellSize of the GridPattern
    // in the Node whose Id is "PrintGrid".
    public void UpdatePrintGrid()
    {
        if (!this.IsPreviewEnabled) return;
        Diagram diagram = this.Diagram;
        if (diagram == null) return;
        if (diagram.Panel == null) return;
        double pw = this.PrintableArea.Width;
        double ph = this.PrintableArea.Height;
        Thickness m = this.Margin;
        pw -= m.Left + m.Right;
        ph -= m.Top + m.Bottom;
        if (pw <= 0 || Double.IsNaN(pw) || ph <= 0 || Double.IsNaN(ph))
        {
            return;  // can't update PrintGrid if we don't know printable area
        }
        Node printGrid = diagram.PartsModel.FindNodeByKey("PrintGrid");
        if (printGrid != null)
        {
            if (((Grid)printGrid.Content).Background != _Background)
            {
                ((Grid)printGrid.Content).Background = _Background;
            }
            Rect db = diagram.Panel.DiagramBounds;
            double scale = this.Scale;
            if (Double.IsNaN(scale) || scale <= 0 || Double.IsInfinity(scale))
            {
                scale = Math.Min(1, Math.Min(pw / db.Width, ph / db.Height));
            }
            Size eps = new Size(pw / scale, ph / scale);
            GridPattern gp = printGrid.FindDescendant(e => e is GridPattern) as GridPattern;
            if (gp != null)
            {
                // update the PrintGrid's position and size to cover the DiagramBounds
                //if (this._Location.X > 0 || this._Location.Y > 0)
                //{
                //    printGrid.Location = this._Location;
                //}
                //else
                //{
                    //printGrid.Location = new Point(db.X, db.Y);
                //}
                printGrid.Location = this._Location;
                if (eps.Width >= db.Width)
                {
                    gp.Width = Math.Ceiling(Math.Ceiling(db.Width / eps.Width) * eps.Width);
                }
                else
                {
                    gp.Width = Math.Ceiling(Math.Ceiling(eps.Width / db.Width) * eps.Width);
                }
                if (eps.Height >= db.Height)
                {
                    gp.Height = Math.Ceiling(Math.Ceiling(db.Height / eps.Height) * eps.Height);
                }
                else
                {
                    gp.Height = Math.Ceiling(Math.Ceiling(eps.Height / db.Height) * eps.Height);
                }
                gp.Margin = this.Margin;
                // update the PrintGrid's GridPattern's CellSize
                gp.CellSize = eps;
            }
        }
    }
}

Best regards

Bernhard

It is suspicious that in Silverlight it thinks there should be two pages, even though only one page “printed”.
If you move the one node more towards the middle of the page, does it print correctly?
If you have several nodes spread out in the page, does it print correctly?

Hi,

unfortunatelly not, neither placing node to the middle or the left top corner, nor placing on every corner a node.

If I choose a greater page format e.g. A3 nothing is shown on the printed page.

Could it be a template problem?

Have you an example of printing GoXam in Silverlight?

Best regards

Yes, several of the samples in GoSilverlightDemo support printing.
And in particular, the Entity Relationship sample from which you adapted the PreviewingPrintManager supports printing.

So I guess the easy thing to check first is if printing in that sample works for you.

If that works, I would guess that there is something different about your code that is causing it to skip a page. That is what I thought when I saw that it was printing information about a second page at the top of the printed sheet.

Note also that in your XPS viewer screenshot there appears to be a cut mark at the very top right corner of the sheet. That is another indication that it thinks the printable area bounds are wrong.

Hi,

ok, I figured out the problem. In my case the DataTemplate is responsible for this issue.

My DataTemplate for ShapeNodes:

If I remove the nested UserControl with Content Databinding, Silverlight prints as expected. It seems to be a general problem with printing Images and Bindings in Silverlight. If the Content Binding delivers null printing in Silverlight fails too.

Do you have any ideas to solve this issue?

Best regards

Bernhard

Yes, it appears that if there is an error during the print rendering process, Silverlight fails. That can happen with images that do not load in time. I’m not sure what the best work-around is. Maybe I can have a better answer next week.