MarqueeControl: MSDN Walkthrough question

J

John D'oh

Hello,

I have been going through the MSDN Walkthrough: Creating a Windows
Forms Control That Takes Advantage of Visual Studio Design-Time
Features.

Everything was going fine and I was able to create and compile the
MarqueeControlLibrary project. And I think I even understood most of
it.

Anyway, at the end of the Walkthrough, they say the next step is to
test the custom control in the designer. In that section of the
Walkthrough, I can get past step 1, but then have problems on step 2.
I create a new usercontrol, DemoMarqueeControl, which derives from the
MarqueeControl. However, when I open this up in Design View and try to
add either the MarqueeText or MarqueeBorder controls to it, the Toolbox
is completely empty. It gives me the message, "There are no usable
controls..." If I right-click and select "Show All", all the controls
show up, but they are disabled.

So I'm wondering if there is a problem with the Walkthrough or if I am
making a mistake somewhere. I'd really love to understand what is
going on and continue learning about custom controls.

Why is the Toolbox empty when I have a derived Usercontrol in Design
View??
 
D

Dave Sexton

Hi,

Is this the walkthrough to which you are referring?

http://msdn2.microsoft.com/en-us/library/35ea88wb(VS.80).aspx

It sounds to me like you're viewing the component designer, not the control
designer.

Does your project build?

Could you verify whether DemoMarqueeControl is actually a descendant of
System.Windows.Forms.UserControl and whether its designer has resize handles
just like that of the Form designer?

FYI, to add an inherited UserControl to your project you should choose
"Inherited User Control" instead of just "User Control" from the "Add New
Item" dialog, and choose the ancestor of the new control from a list
provided by Visual Studio. The list is populated with all classes in the
current project and referenced assemblies that inherit from UserControl.
 
J

John D'oh

Is this the walkthrough to which you are referring?
Yeah, that's the one.
Does your project build?
Yes, the project builds.
Could you verify whether DemoMarqueeControl is actually a descendant of
System.Windows.Forms.UserControl and whether its designer has resize handles
just like that of the Form designer?
It is a descendant of MarqueeControl, not UserControl. And it does
have resize handles in the designer. I can resize the
DemoMarqueeControl, I just can't add anything to it because the Toolbox
is empty.
Here's the code from DemoMarqueeControl.cs after I add it to the
project:
namespace MarqueeControlTest
{
public partial class DemoMarqueeControl : MarqueeControl
{
public DemoMarqueeControl()
{
InitializeComponent();
}
}
}
FYI, to add an inherited UserControl to your project you should choose
"Inherited User Control" instead of just "User Control" from the "Add New
Item" dialog, and choose the ancestor of the new control from a list
provided by Visual Studio. The list is populated with all classes in the
current project and referenced assemblies that inherit from UserControl.
Thanks for the tip. I used that method to add a DemoMarqueeControl2 to
the MarqueeControlTest project and the result was the same. I can
resize the control in the designer, but the Toolbox is empty, so I
can't add a MarqueeBorder or MarqueeText control to it.

It seems like the MarqueeControl isn't acting like a container which
can host other controls. If I go to the Form1 designer (where things
show up in the Toolbox), I can add a MarqueeControl. Then if I try to
add a MarqueeBorder (or MarqueeText) control in it, the control is just
placed on top of the MarqueeControl. It's added to Form1's
controlCollection, not MarqueeControl's controlCollection.

If I go to MarqueeControl's design view in the ControlLibrary project,
I can add a MarqueeText or MarqueeBorder to it without any problems.
 
D

Dave Sexton

Hi,

It is a descendant of MarqueeControl, not UserControl. And it does
have resize handles in the designer.

If MarqueeControl derives from UserControl and DemoMarqueeControl derives
from MarqueeControl, then DemoMarqueeControl is a descendant of UserControl
as well. Since resize handles appear I'll just assume that it is a
UserControl and you are viewing the control designer, not the component
designer, as I originally suspected.

Thanks for the tip. I used that method to add a DemoMarqueeControl2 to
the MarqueeControlTest project and the result was the same. I can
resize the control in the designer, but the Toolbox is empty, so I
can't add a MarqueeBorder or MarqueeText control to it.

What happens if you right-mouse click the empty space in the Toolbox and
select "Reset Toolbox"?
It seems like the MarqueeControl isn't acting like a container which
can host other controls. If I go to the Form1 designer (where things
show up in the Toolbox), I can add a MarqueeControl. Then if I try to
add a MarqueeBorder (or MarqueeText) control in it, the control is just
placed on top of the MarqueeControl. It's added to Form1's
controlCollection, not MarqueeControl's controlCollection.

That is the expected behavior for UserControls when added to another
designer. UserControls provide an encapsulated GUI much like other
controls, but with their own design-time interface. For example, you can't
drag and drop controls into a Label or PictureBox either.

If you want the behavior that you have expressed here for your control then
you should derive from ContainerControl, for instance, but then you won't
have a control designer; only a component designer will be provided by
Visual Studio.
If I go to MarqueeControl's design view in the ControlLibrary project,
I can add a MarqueeText or MarqueeBorder to it without any problems.

Well, at least that is working for you :)
 
J

John D'oh

Hey,
If MarqueeControl derives from UserControl and DemoMarqueeControl derives
from MarqueeControl, then DemoMarqueeControl is a descendant of UserControl
as well. Since resize handles appear I'll just assume that it is a
UserControl and you are viewing the control designer, not the component
designer, as I originally suspected.
Sorry, maybe I'm confused on the difference between the component
designer and control designer. But what you said about
DemoMarqueeControl being a descendant of UserControl is correct and it
is how I understand it.

When I double-click on DemoMarqueeControl.cs in the Solution Explorer,
it opens up a designer. I guess I don't know the name of that
designer.

By the way, I have no idea what I did, but things are now working. I
see only MarqueeText & MarqueeBorder in the Toolbox when in the
designer for DemoMarqueeControl (and DemoMarqueeControl2). I even
created a DemoMarqueeControl3 and it works as well.

Aargh, now I don't think I'll ever be able to figure out what the
problem was. If you have any ideas, I'd love to know what I initially
did wrong.

By the way, I did a Reset Toolbox and that didn't change anything.
That is the expected behavior for UserControls when added to another
designer. UserControls provide an encapsulated GUI much like other
controls, but with their own design-time interface. For example, you can't
drag and drop controls into a Label or PictureBox either.
I guess this is the part I don't understand. As far as I understood,
MarqueeControl is an empty UserControl. I thought it's purpose was to
hold MarqueeText & MarqueeBorder controls (as well as any other
controls) and provide some methods (Start() & Stop() ) to control the
animation. So I assumed that if I opened MarqueeControl or
DemoMarqueeControl in a designer, I would be able to add other controls
in it. Therefore, MarqueeControl or DemoMarqueeControl would act like
a Panel and be the parent of the controls I added. Am I understanding
things correctly?

And since you've been so helpful, I'm hoping you can answer 1 more
question for me. What is the code that tells the Toolbox to show
MarqueeText & MarqueeBorder when in the designer for
DemoMarqueeControl.

Is it these lines that were put in MarqueeControlRootDesigner.cs?
[ToolboxItemFilter("MarqueeControlLibrary.MarqueeBorder",
ToolboxItemFilterType.Require)]
[ToolboxItemFilter("MarqueeControlLibrary.MarqueeText",
ToolboxItemFilterType.Require)]

Thanks again.
 
D

Dave Sexton

Hi,

When I double-click on DemoMarqueeControl.cs in the Solution Explorer,
it opens up a designer. I guess I don't know the name of that
designer.

Since it has resize handles, as you've mentioned already, you will be
designing the control. If you add a component to your designer from the
Toolbox (e.g., BackgroundWorker or FileSystemWatcher) then you'll see the
component tray appear at the bottom of the control designer. The component
designer is basically a full-screen component tray. There are no resize
handles and no "visual" way to design the graphical interface of the
component. Therefore, you are limited to only being able to add components
from the Toolbox, but not controls that provide a graphical interface. If
you want to see the component designer, create a class that derives from
System.ComponentModel.Component instead of UserControl.
By the way, I have no idea what I did, but things are now working. I
see only MarqueeText & MarqueeBorder in the Toolbox when in the
designer for DemoMarqueeControl (and DemoMarqueeControl2). I even
created a DemoMarqueeControl3 and it works as well.
:)

Aargh, now I don't think I'll ever be able to figure out what the
problem was. If you have any ideas, I'd love to know what I initially
did wrong.

I'm still not sure what went wrong.
I guess this is the part I don't understand. As far as I understood,
MarqueeControl is an empty UserControl. I thought it's purpose was to
hold MarqueeText & MarqueeBorder controls (as well as any other
controls) and provide some methods (Start() & Stop() ) to control the
animation. So I assumed that if I opened MarqueeControl or
DemoMarqueeControl in a designer, I would be able to add other controls
in it.

Within its own designer or that of its derived controls, yes.
Therefore, MarqueeControl or DemoMarqueeControl would act like
a Panel and be the parent of the controls I added. Am I understanding
things correctly?

No. When a UserControl is added to a Form's designer, for example, it
shouldn't behave like a Panel. The idea is that a UserControl encapsulates,
usually compositing, a graphical interface. When you add the UserControl to
a Form's designer you should think of it as a standard control such as a
TextBox or Label. If you want a control that behaves as Panel does, then
you must derive from Panel or ContainerControl, for example, but not
UserControl (an alternative to inheritance is to use the appropriate
designer, which I believe is ParentControlDesigner, IIRC).
And since you've been so helpful, I'm hoping you can answer 1 more
question for me. What is the code that tells the Toolbox to show
MarqueeText & MarqueeBorder when in the designer for
DemoMarqueeControl.

Is it these lines that were put in MarqueeControlRootDesigner.cs?
[ToolboxItemFilter("MarqueeControlLibrary.MarqueeBorder",
ToolboxItemFilterType.Require)]
[ToolboxItemFilter("MarqueeControlLibrary.MarqueeText",
ToolboxItemFilterType.Require)]

Actually, I believe that those two lines are the reason that every item is
disabled except for MarqueeBorder and MarqueeText :)

Normally, you don't add any ToolboxItemFilterAttributes to your custom
controls or designers so that all classes that derive from Control (TextBox,
Label and UserControls, for example) are available in the Toolbox.

So it seems that the tutorial did not intend for MarqueeControl and its
derived classes to contain just any Control, but only the two listed above.
If you change "Require" to "Allow", or just remove both of the attributes
from MarqueeControlRootDesigner altogether, then you should be able to add
all Controls to the MarqueeControl's designer from the Toolbox and not just
the two listed above. If not, then try removing the ToolboxItemFilter
attributes from the MarqueeBorder and MarqueeText controls as well. I'm not
sure of the exact behavior of ToolboxItemFilterAttribute since I haven't
used it myself.
 
J

John D'oh

Hi,
I'm still not sure what went wrong.
Now that I look back on it, I'm wondering if your tip about "Reset
Toolbox" is what finally got things working.
If you add a component to your designer from the
Toolbox (e.g., BackgroundWorker or FileSystemWatcher) then you'll see the
component tray appear at the bottom of the control designer. The component
designer is basically a full-screen component tray. There are no resize
handles and no "visual" way to design the graphical interface of the
component. Therefore, you are limited to only being able to add components
from the Toolbox, but not controls that provide a graphical interface. If
you want to see the component designer, create a class that derives from
System.ComponentModel.Component instead of UserControl.
OK, I understand and know what you're talking about. I've just always
called both of them the designers and never distinguished the two.
Thanks for clearing that up.
shouldn't behave like a Panel. The idea is that a UserControl encapsulates,
usually compositing, a graphical interface. When you add the UserControl to
a Form's designer you should think of it as a standard control such as a
TextBox or Label. If you want a control that behaves as Panel does, then
you must derive from Panel or ContainerControl, for example, but not
UserControl (an alternative to inheritance is to use the appropriate
designer, which I believe is ParentControlDesigner, IIRC).
OK, I understand this now and it makes perfect sense.
So it seems that the tutorial did not intend for MarqueeControl and its
derived classes to contain just any Control, but only the two listed above.
If you change "Require" to "Allow", or just remove both of the attributes
from MarqueeControlRootDesigner altogether, then you should be able to add
all Controls to the MarqueeControl's designer from the Toolbox and not just
the two listed above. If not, then try removing the ToolboxItemFilter
attributes from the MarqueeBorder and MarqueeText controls as well. I'm not
sure of the exact behavior of ToolboxItemFilterAttribute since I haven't
used it myself.
I commented out the two lines (and also tried changing "Require" to
"Allow") in the root designer and all controls are now visible in the
toolbox. So even though you've never used ToolboxItemFilterAttribute,
your understanding of it is correct.

I didn't touch the attribute in MarqueeBorder & MarqueeText. I guess I
don't understand the purpose of including the attribute there, but I
can live with that.

Thanks again for all of your help.
 
D

Dave Sexton

Hi,
I commented out the two lines (and also tried changing "Require" to
"Allow") in the root designer and all controls are now visible in the
toolbox. So even though you've never used ToolboxItemFilterAttribute,
your understanding of it is correct.

Thanks for the verification :)
I didn't touch the attribute in MarqueeBorder & MarqueeText. I guess I
don't understand the purpose of including the attribute there, but I
can live with that.

If you're curious, the following article provides some information about how
the Toolbox uses the ToolboxItemFilterAttribute when its present on a
component or a designer class:

"ToolboxItemFilterType Enumeration"
http://msdn2.microsoft.com/en-us/library/system.componentmodel.toolboxitemfiltertype.aspx
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top