Subclass built-in WinForms control? - c#

I've come across the feature in Visual studio to auto-generate a subclass of a custom control using Add New Inherited User Control.
But I haven't found a clear description on how to e.g create a subclass of Button for instance. Apart from the actual way to do it, I'm also interested if VS provides helpful code-generation for this?

You just create your own class that inherits the Control, that you would like to subclass. For instance:
class BetterButton : Button { ...}
That is the easy part. Now you have the option to override various methods or properties, depending on what you want to achieve with your new Control. It could be anything, really. One thing I often see used is overriding OnPaint to get the control drawn in a custom way; and still getting the behaviour of the original control.
In terms of UserControls, I often see that a "parent" UserControl contains some UI logic and basic UI elements, while the subclassed controls are refinements of the parent for specific use.

Related

Change winforms control at runtime

I have inherited user controls in the following manner:
ControlBase
|__ControlInherited1
|__ControlInherited2
ControlBase contains methods and properties that are overridden in each inherited control, but it has no other controls at all. Inherited controls override the base methods and have sub-controls on them and totally different from each other.
I have the ControlBase added to the form, and I want to change it to either ControlInherited1 or ControlInherited2 depending on run-time conditions.
I'd like to take advantage of the inheritance so I do not have to add different routines for every inherited class
I tried the simple controlBase = new ControlInherited1(); line, but the objects of ControlInherited1 control is not displayed on the form.
Is such visual inheritance even possible?
The problem you have is that even if your new control is inherited from the base control, there's no automatic way of applying the existing properties to the new one you're adding with the call controlBase = new ControlInherited1();. In essence, you'll lose all information about the original control when overwrite the original variable by creating a new instance of the ControlInherited1 class and setting it as the value of controlBase.
The correct way to replace an existing control would be to first remove the existing control and then adding the other one to the form, like following:
this.Controls.Remove(controlBase);
this.Controls.Add(newControl);
On top of this, you'll have to do some manual work to make sure all the properties that you want to persist from the original control are applied to the new (replaced) one.

Controls on inherited form are locked, can it be undone?

Setup:
I have created a Form that I wish to have serve as the base from which I will inherit other forms. This base form serves as a "template" of sorts, but it also provides a good deal of functionality related to the structure, as well as the interrelation of all of the controls provided.
A primer for the images that follow... The top info-colored bar is a custom control inherited from ToolStrip. The bottom strip is another custom, again inherited from ToolStrip. The left white block is a TreeView and the right block is a TabControl (having deleted all TabPages from it...I intend for these to be added in the inherited forms).
Image of base form in designer:
Image of inherited form in designer:
Clearly, the only difference is that when I open the inherited form, I get a little box icon superimposed over each control, and when I click them, I get the padlock telling me I cannot edit.
The problems:
All controls on the inherited form are locked. I have researched the issue of visual inheritance, and as far as I can tell, I'm not using any controls that expressly do not support it, as this link suggests there are. In this Q&A, Hans suggests changing the modifier on those controls, which I have done. In fact, I tried both Public and Protected, all to no good result.
I am stumped.
This is a technical restriction in the designer, it is specific to the SplitContainer control you are using. And some other ones. The trouble-maker is the ISupportInitialize interface.
Controls use this interface when they can't afford the properties of the control to be assigned in an arbitrary order. The designer helps when it sees that the control implements this interface, it calls the BeginInit() method when it starts assigning properties, EndInit() when it is done. The control uses these methods to delay the side-effect of property assignments, the EndInit() method makes them effective. Important for SplitContainer, the minimum sizes of the panels also affect the splitter position.
Perhaps you can see the rub, the InitializeComponent() method in the base form class has already called ISupportInitialize.EndInit(). So modifying properties again in the derived form class is unlikely to turn out well. The designer protects the control from this by locking it.
Very inconvenient, there is no simple workaround. If modifying the SplitContainer in the derived form class is a hard requirement then you'll have to give up on inheriting it or write the code by hand in the derived class constructor.

What to extend for a new custom control?

Some people suggest to just extend Panel but I also know about UserControl that sounds like something I should extend to make my own control.
Panel vs. UserControl vs. Control vs. another_alternative
// inheritance depth:
Control
Panel : ScrollableControl : Control
UserControl : ContainerControl : ScrollableControl : Control
All I need is a rectangle to draw and full WinApi ability (Handle, WndProc etc.). But I want to avoid all the extras that might come into the play. I want to use my custom controls to add them to standard forms. No extreme actions.
On the other hand UserControl extends ContainerControl that might have functionality I want (I'm not sure).
I inherited from Control for an OpenGL box and some other simple controls. They work fine so far. I haven't noticed any functionality-loss. Does something speak against Control ? (in case I don't require any extra functionality)
I think the unofficial and accepted "standard" is to just inherit from UserControl. At least that's what I've seen everywhere else. That does not make it the right thing though!
On the other hand, I think you also may be too concerned about the "right thing" to do here. To me, this is almost similar to premature optimization. You want to make sure that you spend your resources wisely.
Also keep in mind that things like this can always be changed later.
If you're concerned for a reason, I would definitely pick the simplest of the controls with the lowest inheritance depth.
Mostly UserControl is the best class to inherit from. Another option could be to inherit from the class that we want to customize.
In your case, Panel should be the best class to inherit from as it is the simplest control class that would serve your requirements.
Panel would be ideal here because you are not defining a layout for the control. Nor does it need a ControlTemplate. Custom rendering schemes generally come with the recommendation to use Panel. While Control is the simplest 'layout' element you can get at, Panel has the ability to host child controls should you need to later. Perfect!
There is a description of what exactly differentiates UserControl from ContentControl in the "Pro WPF" book, which gives more information than MSDN. Here is a direct link to the section:
http://books.google.ca/books?id=znAVMHNSen0C&pg=PA518&lpg=PA518&dq=%22taking+a+closer+look+at+user+controls%22&source=bl&ots=DjZT-9JCQd&sig=R4MoAzW72PaHvqgZjxPnkkJRs6c&hl=en&sa=X&ei=OdQIUrPgDeTYyAGl6oHYAQ&ved=0CC8Q6AEwAQ#v=onepage&q=%22taking%20a%20closer%20look%20at%20user%20controls%22&f=false
The most interesting difference is how it handles routed events. All events raised by contained elements have their Source reset to the UserControl itself.
I think the conceptual difference is that a ContentControl "contains" its content, while a UserControl's content is "part of" the UserControl. Thus a ContentControl is a distinct element (is focusable / a tab stop) whose contents are handled separately; and setting the content of a UserControl is part of its design process, whose elements are handled directly in the UserControl's code-behind.
So, my rules are:
If the user is meant to inherit it and handle content in code-behind, inherit UserControl.
If it's meant to be used as-is and given arbitrary content, inherit ContentControl.
If it defines its own content, and doesn't have a placeholder for arbitrary content, inherit Control and set its Template.
If you just want a rendering surface, I don't think you would need a Control. You can use an ImageSource for this, like InteropBitmap or D3DImage, which can be attached to an ImageBrush. For example, it could be used in a stand-alone rectangle:
<Rectangle>
<Rectangle.Fill>
<ImageBrush>
<ImageBrush.ImageSource>
<!-- ImageSource here -->
</ImageBrush.ImageSource>
</ImageBrush>
</Rectangle.Fill>
<Rectangle>
Or anywhere else that accepts a Brush, including the Background of another control.

Which design pattern is used to give a class extra properties?

When you have a TableLayoutPanel on your Form and you drag a Label into a cell, a few properties are available on the Label control. I think the same construction is used when you drag a Tooltip control on the form.
I'd like to know which design pattern is used to achieve this. Is this the decorator pattern?
What you are seeing are called Extender Providers.
For example, when a ToolTip component is added to a form, it provides
a property called ToolTip to each control on that form. The ToolTip
property then appears in any attached PropertyGrid control.
http://msdn.microsoft.com/en-us/library/ms171836.aspx
I can't think of a well-known pattern that describes how they work, exactly, but the mechanism is simple.
You must implement IExtenderProvider. The WinForms Designer will call CanExtend for each other control on the surface, and your extender can specify if it provides additional attributes for each control.
public interface IExtenderProvider {
bool CanExtend(object extendee);
}
The actual attributes that other controls will be extended are declared using the ProvidePropertyAttribute and a method to provide the value.
No, this is not achieved through a design pattern. These properties are simply the public properties exposed by the control, these properties are added to the control via inheritence, i.e. they sub-class Control. The visual studio designer inspects the class which implements these controls to determine the properties they expose, then provides you with a UI for setting them.

Editing Custom Controls or Panels in the Designer environment

I have created a custom control that inherits System.Windows.Forms.Panel, and adds a few extra properties. I then intend to create child classes that inherit this custom-panel class, and add content to them.
The custom-panel class will be passed to a "Wizard" framework (with back/next buttons) as the content for the various steps. I intend to make extensive use of this, creating 40-50 different pages for Wizards to handle various things in my project.
Question: Is there a way to view just the panel in the Designer, and modify its layout and design from there? I could code everything the hard way, but I really don't want to.
I did some searching and found this article, but that discusses creating a custom control and adding it to a library. I don't need to do this, I just want to view/edit the control in Designer directly, without adding it to a Form.
Obvious Answer to the rescue again.
Create a custom control, add the layout/split panel as desired, and change it's property to DockStyle.Fill.
This makes your custom control "behave" like the layout control, as long as you add all other controls to the layout control.
add first this name space
using System.ComponentModel.Design;
Apply the System.ComponentModel.DesignerAttribute attribute to the control as follows:
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public class UserControl1 : System.Windows.Forms.UserControl
{
...
}
now you can edit your custom user control in designer environment

Categories

Resources