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