What you’re seeing is our default encapsulation model for user controls. By default, a user control is treated as a single object when placed on a form. We do this because it may not be your intent to expose the inner layout of your user control (for example, the PropertyGrid control contains several panels, buttons, scroll bars, etc, but it is treated as a single control).
You can change this default behavior. You have two options which depend on what you want:
If you want the entire surface of your user control to be interactive at design time�br/> In this scenario you want the user control to behave just like it does when it is open in the designer. The user can manipulate all controls within the user control. I wouldn’t recommend this if you want your app to be robust over a long period of time (a user control is about encapsulation, after all, and exposing its internals breaks that).
This is easy to do. You need to change the designer on your user control:
[Designer(typeof(ParentControlDesigner))] public class MyUserControl : UserControl {}
Once you do this, the user control can be edited on the form designer’s surface.
If you want a region of “content�nbsp;on your user control to be interactive at design time�br/> This is the more likely case �nbsp;you have a control with some child controls on it, but one (or more) of the child controls needs to be a content area where the user can drop additional controls. Within this content area you want the user to be able to select, drag, drop and otherwise manipulate controls, but outside of the area you want the user control to be treated as a single entity.
This is easy to do in Whidbey. If you need to target .NET 1.1 or 1.0, it is much harder. For whidbey, you need to do two things:
Add a public read-only property to your user control that exposes the child content control. Write a simple designer that enables the content control to be designed. Here’s the first step:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public Panel MyChildPanel { get { return _myChildPanel; } }
The attribute on the property tells the code generator to write out code for the value contained in this property (normally, read-only properties are skipped).
Here’s the second:
[Designer(typeof(MyUserControlDesigner))] public class MyUserControl : UserControl {
}
class MyUserControlDesigner : ControlDesigner { public override void Initialize(IComponent comp) { base.Initialize(comp); MyUserControl uc = (MyUserControl)comp; EnableDesignMode(uc.MyChildPanel, “MyChildPanel�; } }
Here I’ve created a designer (which can…and should be an internal class unless you specifically design for extensibility). In the initialize code for the designer I’ve called EnableDesignMode, passing the panel I want to enable (MyChildPanel), and a text name that will be shown to the user when the panel is selected (“MyChildPanel�.
Once you do this, the panel will work in the designer. If you click on it, it will be selected and you can set properties on it in the property window. The name for the selected panel will be a mix of the control’s name and the name you provided. For a control named myUserControl1, the panel’s name in the grid will show up as “myUserControl1.MyChildPanel�
Thanks, -Dinesh Chandnani
|