I have a UserControl with some predefined controls (groupbox,button,datagridview) on it, these controls are marked as protected and the components variable is also marked as protected.
I then want to inherit from this base UserControl to another UserControl, however the DataGridView is always locked in the designer.
I suspect it may have something to do with the DataGridView implementing ISupportInitilize.
public class BaseGridDetail : UserControl
Has a DataGridView control (et al) defined.
public class InheritedDetail : BaseGridDetail
The DataGridView control is locked
Does anyone have any ideas how to make this control available in the designer after inheritenace?
By the looks of it, DataListView (and some other controls) do not support visual inheritance. There's a connect issue logged here which doesn't look hopeful.
There have been similar issues logged with other form controls, e.g. flowlayoutpanel.
I'm unable to find a way to force visual inheritance.
Here's the official answer on connect:
"For this particular release, the DataGridView was not designed to be used in visual intheritance. We will keep your suggestion in mind when we plan our future release"
That is of 26/05/2006.
Update: found this blog post which may have the answer
Edit: I was unable to verify the blog post's claims.
Looks like might be the latest on this issue
It looks like you can still manipulate the DataListView at runtime though, so you might be able to set visual properties (and other settings). It's not a great compromise.
[1] create Your Custom UserControl
[2] make your custom userControl use the below Inherited DataGridView:
[Designer(typeof System.Windows.Forms.Design.ControlDesigner))]
public class InheritedDataGridView : DataGridView { }
[3] Inherit from your Custom UserControl , And viola !!
[4] Ohh dont forget to add "System.Design" dll
Enjoy.
Add the datagrid to a panel control and set the modifiers of the panel and the datagrid to protected. This will all your inherited form design time access to the properties of the grid.
I left an answer but re-read your question and decided to delete it.
What is it about the DataGridView that you're trying to modify in the inherited control? It's columns? I've been able to do this by setting up a protected method in my base UserControl and passing the grid's column collection into it, like this:
// in base UserControl
public BaseGridDetail()
{
InitializeComponent();
InitGridColumns(dataGridView1.Columns);
}
protected virtual void InitGridColumns(DataGridViewColumnCollection columns)
{
columns.Clear();
}
Now your derived control can simply override that method, like so:
// in InheritedDetail
protected override void InitGridColumns(DataGridViewColumnCollection columns)
{
base.InitGridColumns(columns);
// add my own custom columns
}
Change property to defined [private] to [protected] defined at xx.designer.cs
which is originally machine generated code.
for example
private System.Windows.Forms.Button btnSave;
to
protected System.Windows.Forms.Button btnSave;
and rebuild it.
then you can change the property of inherited control.
Related
I have class derived from Form and it contains a TableLayoutPanel and in it one Label and one Panel. When I create instance of this Form, all properties and events of controls in design editor are read-only. Is there any way how to expose whole object for editing? I know that I can expose properties one by one, but that is not the best way in case when you want all of them.
Have a look here:
Avoid Visual Inheritance
The TableLayoutPanel control does not support visual inheritance in
the Windows Forms Designer. A TableLayoutPanel control in a
derived class appears as locked at design time.
You can use internal or make a getter method / property
public Label GetLabel() => return someLabel;
or
public Label MyLabel { get { return someLabel; } }
or
internal Label someLabel;
I am trying to add some fields to a custom UserControl that I am making. I have some fields that I like them to be visible in the Properties window of Visual Studio. I tried to use the flags below but I dont see the field in the designer, even after a compile.
How should I do this correctly?
public partial class TosChartControl: UserControl
{
#region PUBLIC FIELDS
[Browsable(true)] //Added this but still does not show up
[Category("Data")]
[DefaultValue(0)]
[Description("ID of the Sensor Node")]
public int NodeId { get; set; }
#endregion
public TosChartControl()
{
InitializeComponent();
}
}
I did clean and rebuild the soloution and projects but I cant still see this field in Properties window. Even restarting the Visualstudio didnt help.
UPDATE: Your public properties are visible in the designer only when it's in another control in the designer. It turns out that you don't need to add this attribute, properties are visible by default in the designer. As far as I understand, when it's in another component's design view, an instance of the user control is created and properties can be shown. Sorry for misleading you in the beginning, I thought it was necessary to add it.
Try this attribute:
[Browsable(true)]
http://msdn.microsoft.com/en-us/library/system.componentmodel.browsableattribute.aspx
To elaborate on henginy's updated answer:
Be sure that you are looking at an instance of the control you want to modify properties for, and not the definition of the control itself.
To clarify, when you add a property to your TosChartControl class, you won't see the property in the TosChartControl.cs [Design] tab, you will see it where you implement a TosChartControl, such as your Form1.cs [Design] tab, e.g. the containing control to which you have added your custom control.
...Assuming that your Properties window is visible, and that you have the control selected.
What to take away from this lesson:
Understanding what the properties window is actually showing you — It's contextual.
The difference between the model and the implementation of the model — e.g. Designing the custom control and designing the form that uses the custom control.
I'm making some controls which all have to share the same look and some common behavior, although they are meant for different kind of inputs. So I made a BaseClass which inherit from UserControl, and all my controls inherit from BaseClass.
However, if i add controls for BaseClass in the designer, such as a TableLayoutPanel, i can't access them when I'm designing the inherited classes. I see the TableLayoutPanel, but even though he is "protected", i can't modify it or put controls in it through the designer. I've no trouble accesing it by code, but i don't want to lose the ability to use the designer.
Right now, i simply removed all controls from BaseClass, added the layout and all the common controls in each of the inherited class, then use references to manipulate them inside BaseClass. But that doesn't satisfy me at all. Is there a way to make the designer work with inherited protected member controls ?
Environment : C#, .NET 3.5, Visual Studio 2008
EDIT to answer SLaks's suggestion. I tried setting a property, and although I'm not used to use them it doesn't seem to work. Here is the code i tried :
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public TableLayoutPanel TableLayoutPanel1
{
get { return tableLayoutPanel1;}
set { tableLayoutPanel1 = value;}
}
}
public partial class UserControl2 : UserControl1
{
public UserControl2()
{
InitializeComponent();
}
}
When you try to access from the inherited control with the designer to the TableLayoutPanel declared in the base control, you're using a feature in WinForms called "Visual Inheritance".
Unfortunately TableLayoutPanel doesn't support visual inheritance:
http://msdn.microsoft.com/en-us/library/ms171689%28VS.80%29.aspx
That's why the TableLayoutPanel appears blocked in the inherited controls.
Try adding this attribute to the definition of the panel (this may or may not help):
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
You have to design the base controls on their own. Changes are reflected in the designer after you successfully rebuild the controls project. If you make the members public you can edit them but the changes won't persist.
Try making a ParentControlDesigner for your control, overriding InternalControlDesigner, and returning (designerHost.GetDesigner(tableLayoutPanel) as ControlDesigner). designerHost is (IDesignerHost) component.Site.GetService(typeof(IDesignerHost)).
I vaguely remember solving a similar problem by putting the base class it its own DLL and building it first. I've had a rummage but I can't find the project. Sorry.
I'd like to create a derived control from System.Windows.Forms.ComboBox that is bound to a list of objects that I retrieve from the database. Idea is other developers can just drop this control on their form without having to worry about the datasource, binding, unless they want to.
I have tried to extend combobox and then set the DataSource, DisplayMember, and ValueMember in the constructor.
public class CustomComboBox : ComboBox
{
public CustomComboBox()
{
this.DataSource = MyDAL.GetItems(); // Returns List<MyItem>
this.DisplayMember = "Name";
this.ValueMember = "ItemID";
}
}
Works when I run, but throws a lot of errors in Visual Studio's once it's added to any form. The error I get is:
"Code generation for property 'Items' failed. Error was: 'Object reference not set to an instance of an object"
What's the correct way to accomplish this (C#, Winforms, .NET 2.0+)?
The problem is that the designer actually does some compilation and execution in a slightly different context than normally running the program does.
In the constructor, you can wrap your code in:
if (!DesignMode)
{
//Do this stuff
}
That will tell the designer to not run any of your initialization code while it is being designed.
DesignMode property doesn't work in a constructor. From googling for a while, found this LicenseManager thing.
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
{
// Do your database/IO/remote call
}
However LicenseManager only works in constructors. For eventhandlers use DesignMode.
Source: http://dotnetfacts.blogspot.com/2009/01/identifying-run-time-and-design-mode.html
Another reference: http://weblogs.asp.net/fmarguerie/archive/2005/03/23/395658.aspx
My usual comment here - DesignMode is not reliable in any situation other than if the control is placed directly on a design surface - i.e. if the control is placed on another control, DesignMode is not true even if you are in design mode. I have found NO reliable way to tell if you are in design mode - especially with inherited controls. Even variants using Site are not reliable if the control is inherited from a non-visual control (e.g. Common Dialog).
See http://keyofdflat.livejournal.com/5407.html (make sure to read the last comment).
Outline
OK, I have Google'd this and already expecting a big fat NO!! But I thought I should ask since I know sometimes there can be the odd little gem of knowledge lurking around in peoples heads ^_^
I am working my way through some excercises in a book for study, and this particular exercise is User Controls. I have cobbled together a control and would like to set the DefaultEvent for it (having done this for previous controls) so when I double-click it, the default event created is whatever I specify it to be.
NOTE: This is a standard User Control (.ascx), NOT a custom rendered control.
Current Code
Here is the class & event definition:
[System.ComponentModel.DefaultEvent("OKClicked")]
public partial class AddressBox : System.Web.UI.UserControl
{
public event EventHandler OKClicked;
Current Result
Now, when I double click the the control when it is on a ASPX page, the following is created:
protected void AddressBox1_Load(object sender, EventArgs e)
{
}
Not quite what I was expecting! So, my question:
Is it possible to define a DefaultEvent for a UserControl? Is it a hack? If it's [not] supported, is there a reason?
Side Note: How do we put underscores in code? I cant seem to put and escape char in?
Here is a possible answer, without testing (like martin did).
In reflector, you will see that the DefaultEventAttribute allows itself to be inherited.
In reflector, you see that the UserControl class has it's default event set to the Load event.
So the possible reason is that even though you are decorating your user control with the default event of OKClick, VS might still be thinking that the default event is load, as it's being inherited from UserControl whose default event is Load.
Just a high level guess at what might be happening.
OK, I checked this out, Inheriting from WebControl rather than UserControl.. All worked fine.
Looks like Darren Kopp takes the crown for this one! Thanks for the input!