nikita
nikita

Reputation: 2817

DesignerHost fails to create control with Visible = false

Good day!

I'm writing a .vsix to replace old controls to new ones. I have designerHost which is the current designer instance. Then I start converting like this:

 foreach (OldCombo oldCmbx in OldCmbxs())
 {
      ...
      NewCombo newCmbx = designerHost.CreateComponent(NewComboType, oldcmbx.Name) as NewCmbx;
      ...
      newCmbx.Visible = oldCmbx.Visible;
      ...
      designerHost.DestroyComponent(oldCmbx);
 }

The thing is -oldCmbx is always Visible=true, no matter how it's written in the designer.cs file. I'm always creating Visible=true newCmbx's. If I force newCmbx to be Visible=false, then designer doesn't show newCmbx after the conversion, but the visible property is still true, so Visible property is definitely not what I'm searching for. So how can I force newCmbx's to be Visible=false in designer.cs?

Upvotes: 3

Views: 368

Answers (1)

nikita
nikita

Reputation: 2817

After digging through .NET source code I've found that ControlDesigner is shadowing Visible property of the Control, so what is going to be serialized/deserialized in InitializeComponent is far related from actual Visible property of Control.

Designer.Visible property is initialized like this:

public override void Initialize(IComponent component)
{
   PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(component.GetType());
   PropertyDescriptor descriptor = properties["Visible"];
   if (((descriptor == null) || (descriptor.PropertyType != typeof(bool))) || !descriptor.ShouldSerializeValue(component))
    {
        this.Visible = true;
    }
    else
    {
        this.Visible = (bool) descriptor.GetValue(component);
    }
    ...
 }

descriptor.ShouldSerializeValue(component) for Control.Visible is always false in case of newly created control.

Designer.Visible property:

private bool Visible
{
    get
    {
        return (bool) base.ShadowProperties["Visible"];
    }
    set
    {
        base.ShadowProperties["Visible"] = value;
    }
}

In the Designer.PreFilterProperties() actual Visible property of the Control is shadowed by Visible property of the designer.

Now, when the designer is initialized(in my code that's happening when I'm creating component designerHost.CreateComponent) newCmbx.Visible is always true.

Why it is so? Because Visible property of the Control is used in painting of the control(on the designer surface as well). If I set newCmbx.Visible = false it just disappears from the design surface (but still serializes from the Visible property of the designer) - that's bad, so by design of the Control class, when Control is instantiated, it is always Visible so that it could be visible on the design surface. Any subsequent changes in Visible property influence Visible property of the designer, not Control itself (in the context of working in Designer mode).

So, what I need in order to solve that problem is Visible property of the designer.

Correct code looks like this:

foreach (OldCombo oldCmbx in OldCmbxs())
{
  bool _visible = GetVisiblePropThroughReflection(designerHost.GetDesigner(oldCmbx));
  ...
  NewCombo newCmbx = designerHost.CreateComponent(NewComboType, oldcmbx.Name) as NewCmbx;
  ...
  SetVisiblePropThroughReflection(designerHost.GetDesigner(newCmbx), _visible);
  ...
  designerHost.DestroyComponent(oldCmbx);
}

Upvotes: 1

Related Questions