Skip to content

Add IsAncestorSiteInDesignMode for Control #4146

Description

@KlausLoeffelmann

Rationale

WinForms Developers need a more reliable way to check, if a custom control is currently in DesignMode. The Problem is that the DesignMode property of Control does only return true, if that control is a) actually sited, and b) then returns the DesignMode property of the Site.

In many cases, DesignMode that does not help: Whenever a control is part of a constituent control (like the TextBox control in NumericUpDown) or a UserControl, the individual controls making up the UserControl (constituent control) never get sited, and although there is a Site technically which could return true for DesignMode, from the perspective of that control, that never happens.

IMPORTANT NOTE: This API's purpose is not to provide a way to check, if a control is currently hosted by a Designer for License purposes, so for them to decide, if for example the Designer UI can be made accessible, if a necessary license is present. We would need a different infrastructure for that.

Proposed API:

Add a read-only property to Control, which returns a boolean:

public bool IsAncestorSiteInDesignMode

IsAncestorSiteInDesignMode would find the first sited root (parent/ancestor) control, test for that being sited and return DesignMode, thus a rather reliable way for a control to decide if according to its context it is considering itself to be in design mode (per the WinForms definition for DesignMode).

Will this feature affect UI controls?

No.

Practically, it could be looking something like this:

        protected bool IsAncestorSiteInDesignMode =>
            GetSitedParentSite(this) is ISite parentSite ? parentSite.DesignMode : false;

        private ISite GetSitedParentSite(Control control) =>
            control is null
                ? throw new ArgumentNullException(nameof(control))
                : control.Site != null || control.Parent is null
                    ? control.Site
                    : GetSitedParentSite(control.Parent);

Real World Scenario

Let's assume we have a custom control, which uses resources, but those resources should only be used at runtime (like connections to a database, or a connection to a web service).

That means, when ever not only this custom control is in its DesignMode...

image

...but also one of it's parents is in their DesignMode...

image

...it should not touch those resources.

As soon, however, as it detects that none of its ancestors is sited (or their sites are not reporting they are in DesignMode) it can assume it's safe to use those runtime-only resources:

image

From the custom control's point of view, such an implementation would look like this:

    class CustomControl : Control
    {
        private Brush _cashedBackColorBrush = new SolidBrush(Color.DarkGray);
        private bool _allowRunTimeOnlyResources;

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            if (!IsAncestorSiteInDesignMode) 
            {
                _allowRunTimeOnlyResources = true;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            string drawText;

            base.OnPaint(e);

                e.Graphics.FillRectangle(_cashedBackColorBrush, ClientRectangle);
                var canOrNot = _allowRunTimeOnlyResources ? "can" : "should not";

                drawText = $"{this.Name} {canOrNot} use runtime resources currently.";
                CenterString(drawText);

            void CenterString(string paintText)
            {
                var textSize = e.Graphics.MeasureString(paintText, Font);

                e.Graphics.DrawString(paintText,
                    Font,
                    Brushes.Black,
                    ClientSize.Width / 2 - textSize.Width / 2,
                    ClientSize.Height / 2 - textSize.Height / 2);
            }
        }
    }

Note, that the test for being sited or not cannot be done in the custom control's constructor. Because at that time, neither the control nor its ancestor can be sited (or rather, it will probably not have ancestors at the time, since it has not been added to any control collection). So, the earliest point in time, when a custom control should check if it has been sited is after its handle got created. And since its handle gets created once the control should display its contends, in most of the cases this is an early enough point in time to decide, whether to use certain (runtime-only) types of resources or not.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

api-approved(4) API was approved in API review, it can be implemented

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions