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.
Related
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.
When the TabPage.Hide() doesn't have any effect why is still available?
tcImgBase.TabPages["tabPage3"].Hide();
The general implementation to hide a tab page is to remove it.
Can someone explain the scope of Hide & Show?
The Hide() method just changes the Visible property. It's implemented in the Control class, which is the base class for all Windows Forms controls. That means that all controls have this method and property and it can't be hidden since that's how C# works. However, it's not meaningful for all controls, such as TagPage and, indeed, the MSDN documentation says as much:
This member is not meaningful for this control.
And later:
To hide a tab in a TabControl, you must remove it from the control's TabPages collection.
Both from: http://msdn.microsoft.com/en-us/library/vstudio/y6e1ah1k(v=vs.100).aspx.
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.
From here I have created a BaseForm, then set all its BaseForm.Designer.cs private members to protected. Then has had a visually inherited/derived Form.
Now I am able to re-size or modify all the controls in the derived Form in design-time except the DataGridView. I am finding the DataGridView as locked in the derived Form, even though it is not locked in the BaseForm.
What can be the reason? What should I look/check for again?
I have a base form like this:
And I have derived a form like this:
It is a known problem..
https://connect.microsoft.com/VisualStudio/feedback/details/284335/designer-prevents-access-to-protected-datagridview-control-in-inherited-form
You can create a user control class and derive from DataGridView class
[Designer(typeof(System.Windows.Forms.Design.ControlDesigner))]
public class MyDataGridViewUserControl : DataGridView { }
I guess that VS designer locks controls that came from base classes. Because you have same initialization code you would change properties of grid inside of base class, that affects all other derived forms.
If you want to change properties of your grid, I would recommend to have separate grid for child form, since it should behave differently.
It seems an issue with some .NET controls.
There's a good writing here:
DataGridView locked on a inherited UserControl
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.