This is a migrated thread and some comments may be shown as answers.

Adding row to empty grid

9 Answers 90 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Thomas
Top achievements
Rank 1
Thomas asked on 01 Sep 2014, 07:58 AM
Hi, I have one problem with Telerik Grid View (version 2014.2.617.40).
I set list with several items as DataSource for GridView and user can add new items by clicking on "Click here to add a new row". But if all items were removed from list this row disappear. Only text "No data to display" is showed.

My collection defined as
ItemsCollection<T> : IBindingList, IList<T> where T : Item
{}

After initialization of list user have empty list and cannot add first row. How I can change this behavior?

Thanks.

9 Answers, 1 is accepted

Sort by
0
Stefan
Telerik team
answered on 01 Sep 2014, 08:43 AM
Hi Thomas,

Thank you for writing.

The "No data to display" text should be shown only when the grid does not have its DataSource property assigned or if its Columns collection is empty. I have tested the described case and on my end the new row still remains in the grid and I can still add rows to it. Please refer to the attached project and video.

If you still experience issues, please get back to me with information how to replicate it and I will look into it.

Regards,
Stefan
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Thomas
Top achievements
Rank 1
answered on 09 Sep 2014, 07:45 AM
Reason of problem was found in implementation of ICustomTypeDescriptor interface. All works fine, when I remove this implementation of ICustomTypeDescriptor. You can find example of class bellow.

001.public class CustomItem : ICustomTypeDescriptor
002.  {
003.    public CustomItem( string name )
004.    {
005.      Name = name;
006.    }
007. 
008.    public string Name
009.    {
010.      get;
011.      set;
012.    }
013. 
014.    #region Implementation of ICustomTypeDescriptor
015.    /// <summary>
016.    /// Returns a collection of custom attributes for this instance of a component.
017.    /// </summary>
018.    /// <returns>
019.    /// An <see cref="T:System.ComponentModel.AttributeCollection"/> containing the attributes for this object.
020.    /// </returns>
021.    public AttributeCollection GetAttributes()
022.    {
023.      return TypeDescriptor.GetAttributes( this );
024.    }
025. 
026.    /// <summary>
027.    /// Returns the class name of this instance of a component.
028.    /// </summary>
029.    /// <returns>
030.    /// The class name of the object, or null if the class does not have a name.
031.    /// </returns>
032.    public string GetClassName()
033.    {
034.      return TypeDescriptor.GetClassName( this );
035.    }
036. 
037.    /// <summary>
038.    /// Returns the name of this instance of a component.
039.    /// </summary>
040.    /// <returns>
041.    /// The name of the object, or null if the object does not have a name.
042.    /// </returns>
043.    public string GetComponentName()
044.    {
045.      return TypeDescriptor.GetComponentName( this );
046.    }
047. 
048.    /// <summary>
049.    /// Returns a type converter for this instance of a component.
050.    /// </summary>
051.    /// <returns>
052.    /// A <see cref="T:System.ComponentModel.TypeConverter"/> that is the converter for this object, or null if there is no <see cref="T:System.ComponentModel.TypeConverter"/> for this object.
053.    /// </returns>
054.    public TypeConverter GetConverter()
055.    {
056.      return TypeDescriptor.GetConverter( this );
057.    }
058. 
059.    /// <summary>
060.    /// Returns the default event for this instance of a component.
061.    /// </summary>
062.    /// <returns>
063.    /// An <see cref="T:System.ComponentModel.EventDescriptor"/> that represents the default event for this object, or null if this object does not have events.
064.    /// </returns>
065.    public EventDescriptor GetDefaultEvent()
066.    {
067.      return TypeDescriptor.GetDefaultEvent( this );
068.    }
069. 
070.    /// <summary>
071.    /// Returns the default property for this instance of a component.
072.    /// </summary>
073.    /// <returns>
074.    /// A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the default property for this object, or null if this object does not have properties.
075.    /// </returns>
076.    public PropertyDescriptor GetDefaultProperty()
077.    {
078.      return TypeDescriptor.GetDefaultProperty( this );
079.    }
080. 
081.    /// <summary>
082.    /// Returns an editor of the specified type for this instance of a component.
083.    /// </summary>
084.    /// <returns>
085.    /// An <see cref="T:System.Object"/> of the specified type that is the editor for this object, or null if the editor cannot be found.
086.    /// </returns>
087.    /// <param name="editorBaseType">A <see cref="T:System.Type"/> that represents the editor for this object. </param>
088.    public object GetEditor( Type editorBaseType )
089.    {
090.      return TypeDescriptor.GetEditor( this, editorBaseType );
091.    }
092. 
093.    /// <summary>
094.    /// Returns the events for this instance of a component.
095.    /// </summary>
096.    /// <returns>
097.    /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the events for this component instance.
098.    /// </returns>
099.    public EventDescriptorCollection GetEvents()
100.    {
101.      return TypeDescriptor.GetEvents( this );
102.    }
103. 
104.    /// <summary>
105.    /// Returns the events for this instance of a component using the specified attribute array as a filter.
106.    /// </summary>
107.    /// <returns>
108.    /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the filtered events for this component instance.
109.    /// </returns>
110.    /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter. </param>
111.    public EventDescriptorCollection GetEvents( Attribute[] attributes )
112.    {
113.      return TypeDescriptor.GetEvents( this, attributes );
114.    }
115. 
116.    /// <summary>
117.    /// Returns the properties for this instance of a component.
118.    /// </summary>
119.    /// <returns>
120.    /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the properties for this component instance.
121.    /// </returns>
122.    public PropertyDescriptorCollection GetProperties()
123.    {
124.      return TypeDescriptor.GetProperties( this );
125.    }
126. 
127.    /// <summary>
128.    /// Returns the properties for this instance of a component using the attribute array as a filter.
129.    /// </summary>
130.    /// <returns>
131.    /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the filtered properties for this component instance.
132.    /// </returns>
133.    /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter. </param>
134.    public PropertyDescriptorCollection GetProperties( Attribute[] attributes )
135.    {
136.      return TypeDescriptor.GetProperties( this, attributes );
137.    }
138. 
139.    /// <summary>
140.    /// Returns an object that contains the property described by the specified property descriptor.
141.    /// </summary>
142.    /// <returns>
143.    /// An <see cref="T:System.Object"/> that represents the owner of the specified property.
144.    /// </returns>
145.    /// <param name="pd">A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the property whose owner is to be found. </param>
146.    public object GetPropertyOwner( PropertyDescriptor pd )
147.    {
148.      return null;
149.    }
150.    #endregion
151.  }

1.

radGridView1.DataSource =
new BindingList<CustomItem>();

Also items which were added programmatically to empty collection are invisible. I cannot remove ICustomTypeDescriptor interface in my case. How I can fix this?
0
Thomas
Top achievements
Rank 1
answered on 09 Sep 2014, 07:46 AM
Reason of problem was found in implementation of ICustomTypeDescriptor interface. All works fine, when I remove this implementation of ICustomTypeDescriptor. You can find example of class bellow.
public class CustomItem : ICustomTypeDescriptor
  {
    public CustomItem( string name )
    {
      Name = name;
    }
 
    public string Name
    {
      get;
      set;
    }
 
    #region Implementation of ICustomTypeDescriptor
    /// <summary>
    /// Returns a collection of custom attributes for this instance of a component.
    /// </summary>
    /// <returns>
    /// An <see cref="T:System.ComponentModel.AttributeCollection"/> containing the attributes for this object.
    /// </returns>
    public AttributeCollection GetAttributes()
    {
      return TypeDescriptor.GetAttributes( this );
    }
 
    /// <summary>
    /// Returns the class name of this instance of a component.
    /// </summary>
    /// <returns>
    /// The class name of the object, or null if the class does not have a name.
    /// </returns>
    public string GetClassName()
    {
      return TypeDescriptor.GetClassName( this );
    }
 
    /// <summary>
    /// Returns the name of this instance of a component.
    /// </summary>
    /// <returns>
    /// The name of the object, or null if the object does not have a name.
    /// </returns>
    public string GetComponentName()
    {
      return TypeDescriptor.GetComponentName( this );
    }
 
    /// <summary>
    /// Returns a type converter for this instance of a component.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.ComponentModel.TypeConverter"/> that is the converter for this object, or null if there is no <see cref="T:System.ComponentModel.TypeConverter"/> for this object.
    /// </returns>
    public TypeConverter GetConverter()
    {
      return TypeDescriptor.GetConverter( this );
    }
 
    /// <summary>
    /// Returns the default event for this instance of a component.
    /// </summary>
    /// <returns>
    /// An <see cref="T:System.ComponentModel.EventDescriptor"/> that represents the default event for this object, or null if this object does not have events.
    /// </returns>
    public EventDescriptor GetDefaultEvent()
    {
      return TypeDescriptor.GetDefaultEvent( this );
    }
 
    /// <summary>
    /// Returns the default property for this instance of a component.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the default property for this object, or null if this object does not have properties.
    /// </returns>
    public PropertyDescriptor GetDefaultProperty()
    {
      return TypeDescriptor.GetDefaultProperty( this );
    }
 
    /// <summary>
    /// Returns an editor of the specified type for this instance of a component.
    /// </summary>
    /// <returns>
    /// An <see cref="T:System.Object"/> of the specified type that is the editor for this object, or null if the editor cannot be found.
    /// </returns>
    /// <param name="editorBaseType">A <see cref="T:System.Type"/> that represents the editor for this object. </param>
    public object GetEditor( Type editorBaseType )
    {
      return TypeDescriptor.GetEditor( this, editorBaseType );
    }
 
    /// <summary>
    /// Returns the events for this instance of a component.
    /// </summary>
    /// <returns>
    /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the events for this component instance.
    /// </returns>
    public EventDescriptorCollection GetEvents()
    {
      return TypeDescriptor.GetEvents( this );
    }
 
    /// <summary>
    /// Returns the events for this instance of a component using the specified attribute array as a filter.
    /// </summary>
    /// <returns>
    /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the filtered events for this component instance.
    /// </returns>
    /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter. </param>
    public EventDescriptorCollection GetEvents( Attribute[] attributes )
    {
      return TypeDescriptor.GetEvents( this, attributes );
    }
 
    /// <summary>
    /// Returns the properties for this instance of a component.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the properties for this component instance.
    /// </returns>
    public PropertyDescriptorCollection GetProperties()
    {
      return TypeDescriptor.GetProperties( this );
    }
 
    /// <summary>
    /// Returns the properties for this instance of a component using the attribute array as a filter.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the filtered properties for this component instance.
    /// </returns>
    /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter. </param>
    public PropertyDescriptorCollection GetProperties( Attribute[] attributes )
    {
      return TypeDescriptor.GetProperties( this, attributes );
    }
 
    /// <summary>
    /// Returns an object that contains the property described by the specified property descriptor.
    /// </summary>
    /// <returns>
    /// An <see cref="T:System.Object"/> that represents the owner of the specified property.
    /// </returns>
    /// <param name="pd">A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the property whose owner is to be found. </param>
    public object GetPropertyOwner( PropertyDescriptor pd )
    {
      return null;
    }
    #endregion
  }
Usage
radGridView1.DataSource = new BindingList<CustomItem>();
Also items which were added programmatically to empty collection are invisible. I cannot remove ICustomTypeDescriptor interface in my case. How I can fix this?
0
George
Telerik team
answered on 11 Sep 2014, 02:56 PM
Hello Thomas,

Thank you for writing back.

The problem was coming from the implementation of the ICustomTypeDescriptor interface. Here's how the GetProperties, GetProperties(Attribute[] attributes) and GetPropertyOwner should be implemented:
public PropertyDescriptorCollection GetProperties()
{
    return TypeDescriptor.GetProperties(this, true);
}
 
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
 
    List<PropertyDescriptor> descriptors = new List<PropertyDescriptor>();
    foreach (PropertyDescriptor descriptor in this.GetProperties())
    {
        bool include = false;
        foreach (Attribute searchAttribute in attributes)
        {
            if (descriptor.Attributes.Contains(searchAttribute))
            {
                include = true;
                break;
            }
        }
        if (include)
        {
            descriptors.Add(descriptor);
        }
    }
 
    return new PropertyDescriptorCollection(descriptors.ToArray());
}
 
public object GetPropertyOwner(PropertyDescriptor pd)
{
    return this;
}

I hope this information will help.

Regards,
George
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Thomas
Top achievements
Rank 1
answered on 15 Sep 2014, 07:24 AM
Hello George,

Thanks you for answer. I implemented your suggestions but it does not work. RadGridView still shows message "No data to display". Can you give me example which will show implementation of ICustomTypeDescriptor for working with RadGridView or link to example.

Thanks.
0
George
Telerik team
answered on 17 Sep 2014, 01:22 PM
Hi Thomas,

Thank you for your reply.

I am attaching a sample project with a RadGridView bound to such items. You can find it below.

Let me know, should you have other questions.

Regards,
George
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Thomas
Top achievements
Rank 1
answered on 17 Sep 2014, 03:29 PM
Hello George,
Thanks you for answer. I downloaded your example and ran it. It works fine but you use not empty BindingList. I wrote that list is empty after initialization and user cannot add first row. When I commented lines 20-24 (Form1.cs) in your example and attached empty BIndingList to DataGridView, row with text "Click here to add a new row" is absent. So user cannot add first row when run program first time. Also I tried to add button for creating first row when list is empty. But It does not work too. New items do not appear in grid. The reason of all issues is ICustomTypeDescriptor. When I removed it from example all forks fine, but I cannot remove it from my project.

I am using version 2014.2.715.40.

How I can fix this?
0
Accepted
Dess | Tech Support Engineer, Principal
Telerik team
answered on 22 Sep 2014, 11:21 AM
Hello Thomas,

Thank you for writing back.

When you bind the grid to a collection of custom objects, the grid automatically generates columns for all of the object's properties according to the properties returned by the CurrencyManager. However, in this case the CurrencyManager will return an empty collection of properties, hence the grid will not create any columns (same is applicable for the .NET DataGridView as well). There are two ways to handle this:

1. In order for the CurrencyManager to return valid property descriptors, the collection holding your items should implement ITypedDescriptor. Here is a sample implementation of such collection:
class MyList : BindingList<CustomItem>, ITypedList
{
    public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        return TypeDescriptor.GetProperties(typeof (CustomItem));
    }
 
    public string GetListName(PropertyDescriptor[] listAccessors)
    {
       return typeof(CustomItem).Name;
    }
}

Then, just bind the grid to this collection.

2. Add at least one dummy CustomItem after initializing the BindingList<CustomItem> which will initialize theCurrencyManager. Afterwards, you can clear the collection. As a result, no records will be displayed in the grid, but the Columns collection will be initialized and the new row will be shown as well.

I hope this information helps. If you have any additional questions, please let me know.

Regards,
Desislava
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Thomas
Top achievements
Rank 1
answered on 08 Oct 2014, 07:28 AM
Thanks for help. ITypedList helped in my case.
Tags
GridView
Asked by
Thomas
Top achievements
Rank 1
Answers by
Stefan
Telerik team
Thomas
Top achievements
Rank 1
George
Telerik team
Dess | Tech Support Engineer, Principal
Telerik team
Share this question
or