Composite
        (
            Double compositeWidth,
            Double compositeHeight,
            String headerText,
            String footerText,
            System.Drawing.Font headerFooterFont,
            IEnumerable <LegendControlBase> legendControls
        )
        {
            Debug.Assert(compositeWidth > 0);
            Debug.Assert(compositeHeight > 0);
            Debug.Assert(headerFooterFont != null);
            Debug.Assert(legendControls != null);
            AssertValid();

            // Note:
            //
            // Don't try taking a shortcut by using
            // NodeXLControl.CopyGraphToBitmap() to get an image of the graph and
            // then compositing the image with the other elements.  That would work
            // if the caller were creating an image, but if it were creating an XPS
            // document, the graph would no longer be scalable.

            Double dScreenDpi =
                WpfGraphicsUtil.GetScreenDpi(m_oNodeXLControl).Width;

            // The NodeXLControl can't be a child of two logical trees, so
            // disconnect it from its parent after saving the current vertex
            // locations.

            m_oLayoutSaver = new LayoutSaver(m_oNodeXLControl.Graph);

            Debug.Assert(m_oNodeXLControl.Parent is Panel);
            m_oParentPanel = (Panel)m_oNodeXLControl.Parent;
            UIElementCollection oParentChildren = m_oParentPanel.Children;

            m_iChildIndex = oParentChildren.IndexOf(m_oNodeXLControl);
            oParentChildren.Remove(m_oNodeXLControl);

            m_oGraphImageScaler = new GraphImageScaler(m_oNodeXLControl);

            m_oGraphImageCenterer = new NodeXLControl.GraphImageCenterer(
                m_oNodeXLControl);

            // The header and footer are rendered as Label controls.  The legend is
            // rendered as a set of Image controls.

            Label oHeaderLabel, oFooterLabel;
            IEnumerable <Image> oLegendImages;
            Double dHeaderHeight, dTotalLegendHeight, dFooterHeight;

            CreateHeaderOrFooterLabel(headerText, compositeWidth, headerFooterFont,
                                      out oHeaderLabel, out dHeaderHeight);

            CreateLegendImages(legendControls, compositeWidth, out oLegendImages,
                               out dTotalLegendHeight);

            CreateHeaderOrFooterLabel(footerText, compositeWidth, headerFooterFont,
                                      out oFooterLabel, out dFooterHeight);

            m_oNodeXLControl.Width = compositeWidth;

            m_oNodeXLControl.Height = Math.Max(10,
                                               compositeHeight - dHeaderHeight - dTotalLegendHeight
                                               - dFooterHeight);

            // Adjust the control's graph scale so that the graph's vertices and
            // edges will be the same relative size in the composite that they are
            // in the control.

            m_oGraphImageScaler.SetGraphScale(
                (Int32)WpfGraphicsUtil.WpfToPx(compositeWidth, dScreenDpi),
                (Int32)WpfGraphicsUtil.WpfToPx(m_oNodeXLControl.Height, dScreenDpi),
                dScreenDpi);

            // Adjust the NodeXLControl's translate transforms so that the
            // composite will be centered on the same point on the graph that the
            // NodeXLControl is centered on.

            m_oGraphImageCenterer.CenterGraphImage(new Size(compositeWidth,
                                                            m_oNodeXLControl.Height));

            StackPanel          oStackPanel         = new StackPanel();
            UIElementCollection oStackPanelChildren = oStackPanel.Children;

            // To avoid a solid black line at the bottom of the header or the top
            // of the footer, which is caused by rounding errors, make the
            // StackPanel background color the same as the header and footer.

            oStackPanel.Background = HeaderFooterBackgroundBrush;

            if (oHeaderLabel != null)
            {
                oStackPanelChildren.Add(oHeaderLabel);
            }

            // Wrap the NodeXLControl in a Grid to clip it.

            m_oGrid              = new Grid();
            m_oGrid.Width        = m_oNodeXLControl.Width;
            m_oGrid.Height       = m_oNodeXLControl.Height;
            m_oGrid.ClipToBounds = true;
            m_oGrid.Children.Add(m_oNodeXLControl);

            oStackPanelChildren.Add(m_oGrid);

            foreach (Image oLegendImage in oLegendImages)
            {
                oStackPanelChildren.Add(oLegendImage);
            }

            if (oFooterLabel != null)
            {
                oStackPanelChildren.Add(oFooterLabel);
            }

            Size oCompositeSize      = new Size(compositeWidth, compositeHeight);
            Rect oCompositeRectangle = new Rect(new Point(), oCompositeSize);

            oStackPanel.Measure(oCompositeSize);
            oStackPanel.Arrange(oCompositeRectangle);
            oStackPanel.UpdateLayout();

            return(oStackPanel);
        }