The user control class contains (aggregates) a DataGridView instance (using
a private modifier). Also, within the user control class, I have a public
property that allows external entities (such as the main form) to access the
inner DataGridView instance like this:
public DataGridView InnerDataGridView
{
get { return this.innerDataGridView; }
}
I compile the project, then open the main form in design mode. It displays
the form that contains the user control instance, that contains the
DataGridView instance. In the Properties window, when I select the user
control instance in the form, I have all user control's public properties, as
expected, including the InnerDataGridView property which has a plus (+/-)
sign in front, allowing me to expand it to read or set properties of the
inner DataGridView instance.
Everything seems right until I try to click the ellipsis button (...) on the
Columns property of the inner DataGridView. This means, in the form I have
selected the user control instance, and in the Properties window I expanded
InnerDataGridView property, selected the Columns [sub-]property, and clicked
on the ellipsis button in the right side.
At this time, Visual Studio designer displays a "object reference not set to
an instance of an object" error in a simple modal message box, and offers no
other details, and this seems to happen within DataGridView (i.e. not in my
code), or I run into a architectural/design restriction which I wasn't aware
of.
(I tried also to create an InnerColumns property in the user control class
that maps to the InnerDataGridView.Columns to have the InnerColumns property
directly in the list of properties of the user control, but even if this way
I didn't receive the message box, and the grid columns editor/designer modal
dialog was open, it wouldn't allow me to create new columns - i.e. when
adding a new column it said that "at least one column doesn't have a
template" and didn't save the column. However, if possible, I don't want to
go through such workarounds for my issue, I think there should be a way to
make the first method work, without the InnerColumns property.)
Does anybody knows more about this issue - why does it happen, and more
important, how can I get over it? I want the end user of my user control
(which will be delivered in a library not in a form in the end) to be able to
set up columns in the inner grid by using the standard columns designer.
Thank you very much in advance,
--
Sorin Dolha, DlhSoft
Robin S.
----------------------------------------------------
"Sorin Dolha" <sdo...@community.nospam> wrote in message
news:2B15D7FC-71C2-40E1...@microsoft.com...
I'll try to figure out a different way (architecture/design) to resolve my
problem.
Thanks,
--
Sorin Dolha, DlhSoft
I have performed a test based on your description and did see the same
thing as you did. I spent several hours researching on this issue.
Yes, you're right. The message box displaying "object reference not set to
an instance of an object" error comes from the
DataGridViewColumnCollectionEditor class, which is the UI type editor of
the Columns property of the DataGridView. The reason why this error occurs
is that the Site property of the DataGridView is NULL. When the
DataGridViewColumnCollectinEditor queries for services, it can't find then
because its site is NULL.
Generally speaking, only components which are placed on the form designer
directly have their Site property set by the form designer host. In your
scenario, the DataGridView is contained within a UserControl. When the
UserControl is dragged&dropped onto a form, only the UserControl instance
has its Site property set, not the DataGridView instance within the
UserControl, i.e. the Site property of the DataGridView remains NULL.
So it seems that the only way to get the DataGridViewColumnCollectionEditor
to work properly is to set the Site property of the DataGridView instance
properly. To do this, we could add the DataGridView instance to the
container collection of the designer host.
The following is a sample code.
private class UserControl1:UserControl
{
public DataGridView InnerDataGridView
{
get { return this.innerDataGridView; }
}
private void UserControl_Load(object, EventArgs e)
{
if (this.DesignMode && this.innerDataGridView.Site == null)
{
this.Site.Container.Add(this.innerDataGridView);
}
}
}
Build the project and switch to the form designer. Now I could edit the
columns of the DataGridView contained in a UserControl using the
DataGridViewColumnCollectionEditor without any error occurring.
Unfortunately, when I run the program, I find that the columns I added at
design-time are missed at run-time. I have a look at the code in the
InitializeComponent method and find that a new DataGridView instance is
created and added to the UserControl and all changes I make using the
Properties window are made to the new DataGridView instance, rather than
the InnerDataGridView instance within the UserControl.
That's to say, my workaround works at design-time but the code
serialization is not what we want.
I will go on researching on how to get the code serialization to be what we
want. As soon as I have any new findings, I will get it back to you.
At the end, I susggest that you add a public property for the
DataGridView's Columns, something like the InnerColumns property you have
mentioned, and implement a custom collection editor based on
CollectionEditor class for the InnerColumns property.
Sincerely,
Linda Liu
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
After doing some more research, I am sorry that I haven't found a
workaround to get the code serialization to be what we want.
I still suggest that you implement a custom collection editor based on
CollectionEditor class for the DataGridView's Columns.
Thank you for your feedback.
I am trying to implement a custom collection editor for the inner
DataGridView columns within a UserControl. The custom collection editor is
derived from CollectionEditor. The following is the code of the custom
collection editor.
using System.ComponentModel.Design;
using System.Windows.Forms;
class MyCollectionEditor:CollectionEditor
{
public MyCollectionEditor(Type type)
: base(type)
{ }
protected override Type CreateCollectionItemType()
{
return typeof(DataGridViewColumn);
}
protected override Type[] CreateNewItemTypes()
{
Type[] types = new Type[] { typeof(DataGridViewTextBoxColumn),
typeof(DataGridViewComboBoxColumn),
typeof(DataGridViewCheckBoxColumn),
typeof(DataGridViewButtonColumn),
typeof(DataGridViewImageColumn),
typeof(DataGridViewLinkColumn)};
return types;
}
protected override object CreateInstance(Type itemType)
{
DataGridViewColumn column =
itemType.GetConstructor(Type.EmptyTypes).Invoke(null) as
DataGridViewColumn;
return column;
}
}
We need to add an EditorAttribute on the inner DataGridView columns
property in the UserControl.
public partial class UserControl1 : UserControl
{
[Editor(typeof(MyCollectionEditor),typeof(UITypeEditor))]
public DataGridViewColumnCollection InnerDGVColumns
{
get { return this.dataGridView1.Columns; }
}
}
Thus, I could edit the columns for the DataGridView within the UserControl
at design-time. However, the problem is that the designer doesn't serialize
the code of the columns of the DataGridView after I add some columns into
the DataGridView at design-time.
I am thinking of using CodeDomSerializer to get the columns serialized
correctly. Unfortunately, I haven't worked it out yet.
I will go on researching on this and will get it back to you ASAP. I
appreciate your patience.
I want to thank you very much for all the efforts you put into this.
Although for us it wasn't a feature that we needed so much that we couldn't
live without it in our project, now we can really implement it. (Of course,
with a few more changes related to column properties serialization - and I
need to do some testing to see if the serializer can use also custom
DataGridViewColumn-derived column types.)
Again, you have our deepest appreciation for all your help and support!
--
Sorin Dolha, DlhSoft
"Linda Liu [MSFT]" wrote:
> Hi Sorin,
>
> Sorry for my delayed response. I have spent much time researching on how to
> serialize the inner DataGridView's columns and finally I got it!
>
> We need to implement a custom CodeDom serializer for the UserControl. The
> custom CodeDom serializer derives from CodeDomSerializer class, which is in
> System.ComponentModel.Design.Serialization namespace. We need to override
> the Deserialize and Serialize methods in the custom CodeDom serializer
> class.
>
> Generally speaking, when we serialize a component, we use the base
> serializer for the component to do it. Unfortunately, the base serializers
> for both the DataGridViewColumnCollection and DataGridViewColumn instance
> could not serialize them at all. So we have to serialize them by ourselves.
>
> System.CodeDom namespace contains classes that can be used to represent the
> elements and structure of a source code document. CodeDOM is often used by
> designers to generate initialization code for component.
>
> The following is the code of the custom CodeDom serializer.
>
> public class MyCodeDomSerializer : CodeDomSerializer
> {
>
> public override object Deserialize(IDesignerSerializationManager
> manager, object codeObject)
> {
> CodeDomSerializer baseClassSerializer =
> (CodeDomSerializer)manager.GetSerializer(typeof(UserControl1).BaseType,
> typeof(CodeDomSerializer));
>
> return baseClassSerializer.Deserialize(manager, codeObject);
>
>
> }
>
> public override object Serialize(IDesignerSerializationManager
> manager, object value)
> {
> CodeDomSerializer baseClassSerializer =
> (CodeDomSerializer)manager.GetSerializer(typeof(UserControl1).BaseType,
> typeof(CodeDomSerializer));
> // serialize the UserControl
> object codeObject = baseClassSerializer.Serialize(manager,
> value);
>
> if (codeObject is CodeStatementCollection)
> {
> CodeStatementCollection statements =
> (CodeStatementCollection)codeObject;
>
> // The code statement collection is valid, so add a comment.
> string commentText = "This comment was added to this object
> by a custom serializer.";
> CodeCommentStatement comment = new
> CodeCommentStatement(commentText);
>
> statements.Insert(0, comment);
> // serialize the inner DataGridView's columns
>
> if (value is UserControl1)
> {
> DataGridViewColumnCollection innercolumns = (value as
> UserControl1).InnerDGVColumns;
> // declare the variable collection of columns in the
> inner DataGridView
> List<CodeVariableReferenceExpression> parameter_list =
> new List<CodeVariableReferenceExpression>();
> CodeArrayCreateExpression createArray = null;
> CodeMethodInvokeExpression methodcall = null;
>
> int i = 1;
>
> CodeStatementCollection col_Statements = null;
> foreach (DataGridViewColumn col in innercolumns)
> {
> /// serialize each column
> col_Statements = new CodeStatementCollection();
>
> CodeObjectCreateExpression col_ObjectCreate = new
> CodeObjectCreateExpression(col.GetType());
>
> CodeVariableDeclarationStatement
> col_VariableDeclaration = new
> CodeVariableDeclarationStatement(col.GetType(), "column" + i.ToString());
>
> CodeAssignStatement col_Assign_Create = new
> CodeAssignStatement(new CodeVariableReferenceExpression("column" +
> i.ToString()), col_ObjectCreate);
> // serialize the Width property of the column
> CodeAssignStatement col_Assign_width = new
> CodeAssignStatement(new CodeVariableReferenceExpression("column" +
> i.ToString() + ".Width"), new CodePrimitiveExpression(col.Width));
>
> CodeFieldReferenceExpression col_FieldReference =
> base.SerializeToExpression(manager, col) as CodeFieldReferenceExpression;
> if (col_FieldReference == null)
> {
> col_Statements.Add(col_VariableDeclaration);
> col_Statements.Add(col_Assign_Create);
> col_Statements.Add(col_Assign_width);
> parameter_list.Add(new
> CodeVariableReferenceExpression("column" + i.ToString()));
> }
>
> ///
>
> statements.AddRange(col_Statements);
> i++;
> }
>
> CodeFieldReferenceExpression target =
> base.SerializeToExpression(manager, value) as CodeFieldReferenceExpression;
> // if the designer hasn't all the columns to the inner
> DataGridView's column collection, add them by ourselves.
> if (target != null && parameter_list.Count > 0)
> {
> createArray = new
> CodeArrayCreateExpression(typeof(DataGridViewColumn),
> parameter_list.ToArray());
> methodcall = new CodeMethodInvokeExpression(new
> CodeVariableReferenceExpression(target.FieldName + ".InnerDGVColumns"),
> "AddRange", createArray);
>
> statements.Add(methodcall);
> }
> }
> }
> return codeObject;
> }
> }
>
> Adorn DesignerSerializerAttribute to the UserControl and
> DesignerSerializationVisibilityAttribute to the property for the inner
> DataGridView's columns.
>
> [DesignerSerializer(typeof(MyCodeDomSerializer),typeof(CodeDomSerializer))]
> public partial class UserControl1 : UserControl
> {
> public UserControl1()
> {
> InitializeComponent();
> }
>
> [Editor(typeof(MyCollectionEditor),typeof(UITypeEditor))]
>
> [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
> public DataGridViewColumnCollection InnerDGVColumns
> {
> get { return this.dataGridView1.Columns; }
> }
> }
>
> I also send you with this reply a sample project that contains both the
> custom UITypeEditor and CodeDom serializer. Please change the attachment's
> file extension .JPG to .ZIP and unzip it on your machine.
>
> Note: in the above sample code and the attached project, I only serialize
> the Width property of a DataGridView column just for an example. I'm sure
> you could serialize other proerties for the DataGridView column in the same
> way.
>
> Please try it and let me know if it is what you want.
Thank you for your prompt feedback.
The custom CodeDom serializer I provide should be able to serialize custom
DataGridViewColumn-derived column types.
Thank your for using our MSDN Managed Newsgroup Support Serive. If you have
any other questions in the future, please don't hesitate to contact us.
It's always our pleasure to be of assistance!
Have a nice week end!
Thanks in advance,
Andrew Larson
Senior Application Developer
Turner & Associates
www.tacnet.com
EggHeadCafe.com - .NET Developer Portal of Choice
http://www.eggheadcafe.com
jpyerule ~AT~ hotmail.com
Thanks !
---
Posted via DotNetSlackers.com
I ran into the same problem. Can you please send me your solution?
Kind regards
Siegmund Baumann
I sure would like this solution as well. I have been working on this
for days. It is weird, I would think that usercontrols with DataGrid's
would be out there somewhere on the web.
Thanks
*** Sent via Developersdex http://www.developersdex.com ***
I would be pleased if you also send me the zip solution :)
I tried to copy paste the code in the current thread but some errors
still occurs when I drag-drop the user control on the main form (it
appears that the embedded datagridview is not instanciated on
serialization).
could you send it to me monesma -at- guidance.lu
Regards,
Thierry
Can you please send me ?
Regards,
Yagnesh
yagnes...@conchango.com
Could you please send me the code-example? The e-mail address is
M8R-1...@mailinator.com. Thank you in advance!!
Kind regards,
Ferry
I ran into the same problem.
Could you please send me the code-example?
Thank you in advance!
Regards,
Evgenia
Just want to say thank you. This block of code have helped a lot in my
development. :)
I am facing the same problem. Can you PL send me the solution code at my
mail address given below:
brajagopal.bhar ~at~ tcs.com
Regards,
Brajagopal Bhar
TATA Consultancy Services Ltd
Would you be so kind to send the sample code to me too since I am facing
the exact same problem?
pdieckmann ~a-t~ yahoo.com
I somehow get the impression that a lot of programmers are working on
this issue.
Therefore I would suggest to post the sample code somewhere where anyone
can access it.
Thank you very much in advance,
Peter Dieckman
Extedo GmbH
I'm the last one who is writing but for sure not the last one facing this
problem. Could you please kindly send also to me the zip with the code sample?
My e-mail is fabrizio.bertussi ~a-t~ libero.it
Thanks in advance,
Fabrizio
"Linda Liu [MSFT]" wrote:
> Hi Sorin,
>
I'm the last one who is writing but for sure not the last one facing this
problem. Could you please kindly send also to me the zip with the code sample?
My e-mail is fabrizio.bertussi ~a-t~ libero.it
Thanks in advance,
Fabrizio
Hi Linda,
I'am about to use your code and it seems to work fine, however i would
like to a the columnnames as class variables instead of
intializecomponent [method] variables.
Can you help, plz
Thanks
Gary Rusher
Thanks in advance.
I am also having tge same problem and seems like you have found a
solution. Can you also forward me the sample code as well?
Thanks in advance,
It would be easier to help you if we new what the original problem was.
What is the question? Your post is orphaned from the original question.
--
Mike
It's always funny to see people reply to years old posts. :-)
--
Armin
Can I please have the sample project.
I'm struggling with the same problem.
Regards Peter
Thank you
melgrubb [at] live (dot) com
"Linda Liu [MSFT]" wrote:
> Hi Sorin,
>