I want my UserControl to automatically update its Region property. I want it to be a combination of child controls' regions merged together.
Here what I have so far:
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
Region region = new Region(new Rectangle(Point.Empty, Size.Empty));
foreach (Control control in Controls)
{
if (control.Region != null)
region.Union(control.Region);
else
region.Union(control.Bounds);
}
Region = region;
Invalidate();
}
Problem is that it does not work: Line region.Union(control.Region);
must be changed because Region does not include information about left and top offset of the control.
What can I do?
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);
}
}