You have a choice of either going for the Rectangles that actually make up a Region. You can get them via GetRegionScans. You can see them in this post.
Or of using the GraphicsPaths your child controls' Regions originate from..
In both methods you can move the controls' region data by its location: Either by offsetting each rectangle or by translating the whole graphicspath.
Here is a code example for the 1st method:
if (control.Region != null)
{
Matrix matrix = new Matrix(); // default, unscaled screen-resolution matrix
var rex = control.Region.GetRegionScans(matrix); // get rectangles
foreach (var r in rex) // use each of them
{
r.Offset(control.Location); // move by the location offsets
region.Union(r);
}
else
{
region.Union(control.Bounds);
}
The problem is that this tends to get slower and slower with the 'vertical' size and the complexity of the Region shapes..
The other way is to keep track of the GraphicsPaths of the child controls.
Assuming a class PathControl with a control property
public GraphicsPath path { get; set; }
You could change the loop maybe to this:
foreach (Control control in Controls)
{
if (control is PathControl)
{
// use a clone, so the original path won't be changed!
GraphicsPath gp = (GraphicsPath)(control as PathControl).path.Clone();
Matrix matrix = new Matrix();
matrix.Translate(control.Left, control.Top);
gp.Transform(matrix); // here we move by the location offsets
region.Union(gp);
else
{
region.Union(control.Bounds);
}
}