Details view under row in gridview

17 posts, 2 answers
  1. Cat
    Cat avatar
    19 posts
    Member since:
    Nov 2010

    Posted 01 Mar 2011 Link to this post

    I'm trying to do something similar to Richard Slate's Row Details Grid, only instead of trying to use a "details" column, I'd like to be able to format the "Details" space with info more like the RadControls example "Custom Views". Is this possible? Basically formatted like the Custom View example, but shown under the row like the Details Grid example.
  2. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 01 Mar 2011 Link to this post

    Hello Cat,

    The Details grid that you mentioned is, as you're probably aware, is just a RadGridView with a column that is designed to span the bottom area. The special part of a Details Grid is that it allows you to show and hide the details area, collapsing and expanding the area.

    The column groups view definition that you mentioned does not allow for that, but you can have a row that spans multiple columns. Depending on your requirement there are a few ideas I could put forward. Please could you let me know more about what you would like to do. If you can attach any screenshots or code samples using the Format Code block, then this may help me to assist you.

    regards,
    Richard
  3. Cat
    Cat avatar
    19 posts
    Member since:
    Nov 2010

    Posted 01 Mar 2011 Link to this post

    I've attached a primitive wireframe to give you an idea. Basically, I'd like to know what the cleanest way to implement this design is. I've been trying to get my head around this for the last two days, and am making poor progress. :(

    One of the challenges is that the design must be conditional. I'm using a "base" gridview for all search results, so some results will have heirarchial dataobjects, and other will be flat objects. I'll only be showing this detail row on certain flat object results.
  4. Answer
    Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 02 Mar 2011 Link to this post

    Hello Cat,

    Well, your wireframe does look like the Row Details Grid. The row details grid though does need to have a column defined as the one to use for the "Row Detail". Here are a couple of suggestions of how to continue:

    1: Use a row details grid. The column that is defined as the row detail can accept HTML by setting the DisableHtmlRendering to false
    Me.GridViewRowDetailsExtended1.Columns(0).DisableHTMLRendering = False
    of course this means that you can add any content in here that you need.

    2: Use a hierachy grid to show one or more child templates for your details. Of course this relies on having related data sources that you can then display but if you have multiple child templates, then this shows nicely in separate tabs. See this help topic for more information

    From the sound of what you are doing, the standard hierarchy grid may be more suitable. I hope this helps but please let me know if you have any questions
    Richard
  5. Cat
    Cat avatar
    19 posts
    Member since:
    Nov 2010

    Posted 02 Mar 2011 Link to this post

    Thanks for the great advice, as usual Richard!

    I think that option #1 that you presented will probably work best, but I'm wary of putting a lot of code into the CellFormatting Handler to populate the extra column during presentation. Option #2 is a bit more complicated for me due to our business rules. Do you have any suggestions for populating the "details" column a little more performantly than using the CellFormatting Handler? All the data I need will be available from the datarow, and the data is read-only. (No add, update, or delete operations.)
  6. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 02 Mar 2011 Link to this post

    Hello Cat,

    You could use the existing RowDetailsGrid in my code library article and if you don't wish to use the CellFormatting event then your data source would need to include all of the HTML Formatting that is required to render the HTML that you need. In my experience though, the CellFormatting event is pretty effective, but I have seen cases where the HTML formatting is in the datasource.

    However, you have mentioned in your first post that you might need hierarchies. Is that correct? If so, then I would need to test the row details grid with a hierarchy but as far as I'm aware, this isn't supported.

    If you just had a flat datasource with one column that contains the formatted text in one of the columns, then I think this would work quite well for your scenario.

    Let me know if you need more details
    Richard
  7. Cat
    Cat avatar
    19 posts
    Member since:
    Nov 2010

    Posted 02 Mar 2011 Link to this post

    I don't think putting the html info into the datasource is an option, but if using the CellFormatting handler is okay, that's what I'm going to do. And the data can be hierarchial, but I'll only be showing the details row on select gridviews that will not be multi-dimensional.  If I can selectively enable/disable the details row, then I simply won't show it for any hierarchial results. Hopefully that still works!

    Maybe you can help me get this up and running though. I've include two screen caps of your DetailsDataGrid, one where the details column's IsVisible property set to false, and one where it's set to true. As you can see, if it's set to false, the layout is correct but I don't actually get any data in the Details column. When set to true, the data shows up, but the layout is all messed up. Got any ideas what I'm doing wrong?
  8. Cat
    Cat avatar
    19 posts
    Member since:
    Nov 2010

    Posted 02 Mar 2011 Link to this post

    Upon further investigation, it appears that the CellFormatting event doesn't pick up the "details" row unless that row is visible. I'm guessing this must be a side-effect of how I'm building the templates for the gridview. Below is the code that I'm currently using to generate the gridview/RowDetailsGrid.

    private RowDetailsGrid CreateGridViewFromSearch(RowDetailsGrid gvResults)
            {
                gvResults.Dock = DockStyle.Fill;
                gvResults.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.None;
                gvResults.ReadOnly = true;
                gvResults.Text = "Test of Hierarchial Data in Grid";
      
                gvResults.ChildViewExpanding += radGridView1_ChildViewExpanding;
                gvResults.CellFormatting += radGridView1_CellFormatting;
      
                gvResults.EnableAllExpand = false;
      
                DataBlob resultsBlob = TestData.GetTestData();
      
                // Set up the master template 
                gvResults.MasterTemplate.AllowAddNewRow = false;
                gvResults.MasterTemplate.AutoGenerateColumns = false;
                gvResults.MasterTemplate.Tag = TestData.MainCollectionName;
                gvResults.DataSource = resultsBlob.Data;
                gvResults.TableElement.BeginUpdate();
                gvResults.MasterTemplate.Columns.Clear();
      
                // This is a named dictionary that contains the column aliases shown on the grid 
                NameAliasSet mainAliasSet = resultsBlob.AliasDictionaries.Where(x => x.CollectionName == TestData.MainCollectionName).FirstOrDefault();
                  
                // Create columns from alias collection 
                foreach (var record in mainAliasSet.ColumnAliases)
                {
                    GridViewTextBoxColumn column = new GridViewTextBoxColumn();
                    column.Name = record.Key;
                    column.HeaderText = record.Value;
                    column.FieldName = record.Key;
                    column.MinWidth = 50;
                    column.MaxWidth = 250;
                    column.AutoSizeMode = BestFitColumnMode.DisplayedDataCells;
      
                    gvResults.MasterTemplate.Columns.Add(column);
                }
      
                gvResults.TableElement.EndUpdate(false);
      
                gvResults.DetailsColumn = radGridView2.Columns["Remarks"];
                radGridView2.Columns["Remarks"].IsVisible = false;
                gvResults.MasterTemplate.BestFitColumns();
      
                return gvResults;
            }

    Comments or suggestions appreciated!
  9. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 02 Mar 2011 Link to this post

    Hi Cat,

    I agree that putting the HTML into the datasource is not an traditional way, but it could have worked hence the suggestion.
    I'll try to put you together a sample as soon as I can.
    Regards,
    Richard
  10. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 02 Mar 2011 Link to this post

    Hello again Cat,

    Ok, I've got a sample for you. I've tried to use the columns that you had in your wireframe model. I've also had to update the RowDetailsGrid itself slightly to cope with the issue of not displaying the "Details" column when in normal mode.

    For starters, you can see a small video that I've made of the functionality.

    And here's the code:

    The Form's Designer File
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.ButtonPopulateHierarchy = new Telerik.WinControls.UI.RadButton();
            this.ButtonPopulateRowDetails = new Telerik.WinControls.UI.RadButton();
            this.gridViewRowDetailsExtended1 = new GridviewRowDetailsExtended.GridViewRowDetailsExtended();
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateHierarchy)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateRowDetails)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.gridViewRowDetailsExtended1)).BeginInit();
            this.SuspendLayout();
            // 
            // ButtonPopulateHierarchy
            // 
            this.ButtonPopulateHierarchy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.ButtonPopulateHierarchy.Location = new System.Drawing.Point(12, 480);
            this.ButtonPopulateHierarchy.Name = "ButtonPopulateHierarchy";
            this.ButtonPopulateHierarchy.Size = new System.Drawing.Size(177, 24);
            this.ButtonPopulateHierarchy.TabIndex = 1;
            this.ButtonPopulateHierarchy.Text = "Populate With Hierarchy Data";
            this.ButtonPopulateHierarchy.Click += new System.EventHandler(this.ButtonPopulateHierarchy_Click);
            // 
            // ButtonPopulateRowDetails
            // 
            this.ButtonPopulateRowDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.ButtonPopulateRowDetails.Location = new System.Drawing.Point(204, 480);
            this.ButtonPopulateRowDetails.Name = "ButtonPopulateRowDetails";
            this.ButtonPopulateRowDetails.Size = new System.Drawing.Size(177, 24);
            this.ButtonPopulateRowDetails.TabIndex = 2;
            this.ButtonPopulateRowDetails.Text = "Populate With Row Details Data";
            this.ButtonPopulateRowDetails.Click += new System.EventHandler(this.ButtonPopulateRowDetails_Click);
            // 
            // gridViewRowDetailsExtended1
            // 
            this.gridViewRowDetailsExtended1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.gridViewRowDetailsExtended1.DetailsColumn = null;
            this.gridViewRowDetailsExtended1.Location = new System.Drawing.Point(12, 12);
            this.gridViewRowDetailsExtended1.Name = "gridViewRowDetailsExtended1";
            this.gridViewRowDetailsExtended1.Size = new System.Drawing.Size(522, 453);
            this.gridViewRowDetailsExtended1.TabIndex = 0;
            this.gridViewRowDetailsExtended1.Text = "gridViewRowDetailsExtended1";
            this.gridViewRowDetailsExtended1.CellFormatting += new Telerik.WinControls.UI.CellFormattingEventHandler(this.gridViewRowDetailsExtended1_CellFormatting);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(543, 516);
            this.Controls.Add(this.ButtonPopulateRowDetails);
            this.Controls.Add(this.ButtonPopulateHierarchy);
            this.Controls.Add(this.gridViewRowDetailsExtended1);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateHierarchy)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateRowDetails)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.gridViewRowDetailsExtended1)).EndInit();
            this.ResumeLayout(false);
        }
        #endregion
        private GridviewRowDetailsExtended.GridViewRowDetailsExtended gridViewRowDetailsExtended1;
        private Telerik.WinControls.UI.RadButton ButtonPopulateHierarchy;
        private Telerik.WinControls.UI.RadButton ButtonPopulateRowDetails;
    }

    The Form1.cs Class
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using Telerik.WinControls.UI;
      
      
        public partial class Form1 : Form
        {
            BindingList<Person> people = new BindingList<Person>();
            BindingList<Child> children = new BindingList<Child>();
      
            public Form1()
            {
                InitializeComponent();
                // set defaults
                this.gridViewRowDetailsExtended1.ReadOnly = true;
                this.gridViewRowDetailsExtended1.ShowFilteringRow = false;
                this.gridViewRowDetailsExtended1.ShowGroupPanel = false;
                this.gridViewRowDetailsExtended1.AutoGenerateColumns = true;
      
                  
            }
      
            private void ButtonPopulateHierarchy_Click(object sender, EventArgs e)
            {
                // reset grid
                this.gridViewRowDetailsExtended1.DataSource = null;
                PopulatePeople();
                PopulateChildren();
      
                // give a data source
                this.gridViewRowDetailsExtended1.DataSource = people;
                this.gridViewRowDetailsExtended1.Columns["Details"].IsVisible = true;
                // new: use row details false
                this.gridViewRowDetailsExtended1.UseRowDetails = false;
                this.gridViewRowDetailsExtended1.ShowRowDetails = false;
                this.gridViewRowDetailsExtended1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill;
      
                // hierarchy stuff - the child template
                GridViewTemplate childTemplate = new GridViewTemplate();
                childTemplate.DataSource = children;
                this.gridViewRowDetailsExtended1.MasterTemplate.Templates.Add(childTemplate);
      
                // set up a relation
                GridViewRelation relation = new GridViewRelation(this.gridViewRowDetailsExtended1.MasterTemplate, childTemplate);
                relation.RelationName = "ParentChildRelation";
                relation.ParentColumnNames.Add("Id");
                relation.ChildColumnNames.Add("ParentId");
                this.gridViewRowDetailsExtended1.Relations.Add(relation);
      
                // best fit the columns
                foreach (GridViewDataColumn column in this.gridViewRowDetailsExtended1.Columns)
                { column.BestFit(); }
            }
      
            private void ButtonPopulateRowDetails_Click(object sender, EventArgs e)
            {
                // reset grid
                this.gridViewRowDetailsExtended1.Relations.Clear();
                this.gridViewRowDetailsExtended1.Templates.Clear();
                this.gridViewRowDetailsExtended1.DataSource = null;
                PopulatePeople();
      
                // data source
                this.gridViewRowDetailsExtended1.DataSource = people;
                // new: use row details true
                this.gridViewRowDetailsExtended1.UseRowDetails = true;
                this.gridViewRowDetailsExtended1.Columns["Details"].IsVisible = false;
                // give it the row details column
                this.gridViewRowDetailsExtended1.DetailsColumn = this.gridViewRowDetailsExtended1.Columns["Details"];
                // show the row details
                this.gridViewRowDetailsExtended1.ShowRowDetails = true;
                this.gridViewRowDetailsExtended1.EnableAllExpand = false;
                this.gridViewRowDetailsExtended1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill;
                // so we can add html to the row details area
                this.gridViewRowDetailsExtended1.Columns["Details"].DisableHTMLRendering = false;
                // best fit the columns
                foreach (GridViewDataColumn column in this.gridViewRowDetailsExtended1.Columns)
                {column.BestFit();}
            }
      
            private void PopulatePeople()
            {
                people.Clear(); 
                people.Add(new Person(1,"Richard", "Mr", DateTime.Now, "WinForms Developer", "Here are some details about Richard"));
                people.Add(new Person(2,"Chris", "Mr", DateTime.Now, "Operations Manager", "Here are some details about Chris"));
                people.Add(new Person(3,"Leisl", "Mrs", DateTime.Now, "Administative Assistant", "Here are some details about Leisl"));
                people.Add(new Person(4,"Chris", "Mr", DateTime.Now, "Cleaner", "Here are some details about Chris"));
                people.Add(new Person(5,"Peter", "Mr", DateTime.Now, "WinForms Developer", "Here are some details about Peter"));
                people.Add(new Person(6,"Ester", "Miss", DateTime.Now, "School Teacher", "Here are some details about Ester"));
            }
      
            private void PopulateChildren()
            {
                children.Clear();
                children.Add(new Child(1, 1, "Javier"));
                children.Add(new Child(2, 2, "Jamie"));
                children.Add(new Child(3, 2, "Max"));
                children.Add(new Child(4, 5, "Zack"));
            }
      
            private void gridViewRowDetailsExtended1_CellFormatting(object sender, Telerik.WinControls.UI.CellFormattingEventArgs e)
            {
                // if it's a row details grid 
                if (this.gridViewRowDetailsExtended1.Relations.Count == 0) 
                
                    // and if its the current row and rowDetails column
                    if (e.CellElement.RowInfo.IsCurrent && e.CellElement.ColumnInfo == this.gridViewRowDetailsExtended1.DetailsColumn)
                    {
                        // set some html and style
                        e.CellElement.DrawFill = true;
                        e.CellElement.GradientStyle = Telerik.WinControls.GradientStyles.Solid;
                        e.CellElement.BackColor = Color.LightBlue;
                        e.CellElement.Padding = new Padding(10);
                        e.CellElement.Text = "<html>" + e.CellElement.Text.Replace("Here", "<strong>Here</strong>") + "</html>";
                    }
                    else
                    {
                        // otherwise reset for UI Virtualization
                        e.CellElement.ResetValue(LightVisualElement.DrawFillProperty, Telerik.WinControls.ValueResetFlags.Local);
                        e.CellElement.ResetValue(LightVisualElement.GradientStyleProperty, Telerik.WinControls.ValueResetFlags.Local);
                        e.CellElement.ResetValue(LightVisualElement.BackColorProperty, Telerik.WinControls.ValueResetFlags.Local);
                        e.CellElement.ResetValue(LightVisualElement.PaddingProperty, Telerik.WinControls.ValueResetFlags.Local);
                    }            
                }
      
      
            }
        }
      
        /// <summary>
        /// Note: Currently, whatever you use for Row Details
        /// cannot be the last column. In this case "Details" is one but last
        /// </summary>
        public class Person
        {
            public Person(int id, string name, string title, DateTime date, string comments, string details)
            {
                this.Id = id;
                this.Name = name;
                this.Title = title; 
                this.Date = date;
                this.Comments = comments;
                this.Details = details;
            }
      
            public int Id
            { get; set; }
      
            public string Name
            {get; set;}
      
            public string Title
            {get; set;}
      
            public DateTime Date
            {get; set;}
      
            public string Details
            { get; set; }
      
            public string Comments
            {get; set;}
      
        }
      
        public class Child
        {
            public Child(int id, int parentId, string name)
            {
                this.Id = id;
                this.ParentId = parentId;
                this.Name = name;
            }
      
            public int Id
            { get; set; }
      
            public int ParentId
            { get; set; }
      
            public string Name
            { get; set; }
      
        }

    And if you've downloaded my code library article code, then here is an updated version of the GridViewRowDetailsExtended.cs class
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Telerik.WinControls.UI;
    using System.ComponentModel;
      
    namespace GridviewRowDetailsExtended
    {
        public class GridViewRowDetailsExtended : RadGridView
        {
            private GridViewDataColumn renamedDetailsColumn;
            private int renamedDetailsRowHeight = 100;
            private bool showRowDetails = true;
            private bool enableAllExpand = true;
            private bool useRowDetails = true;
      
            public GridViewRowDetailsExtended()
            {
                this.GridBehavior = new RowDetailsBehavior();
                this.ViewDefinition = new RowDetailsViewDefinition();
            }
      
            public override string ThemeClassName
            {
                get { return typeof(RadGridView).FullName; }
                set { }
            }
      
            public bool UseRowDetails
            {
                get { return useRowDetails; }
                set { useRowDetails = value; }
            }
      
            [Browsable(false)]
            [Category("Row Details")]
            public GridViewDataColumn DetailsColumn
            {
                get { return this.renamedDetailsColumn; }
      
                set
                {
                    if (!object.ReferenceEquals(renamedDetailsColumn, value))
                    {
                        if (useRowDetails == true)
                        
                            renamedDetailsColumn = value;
                            if (renamedDetailsColumn != null)
                            {
                                renamedDetailsColumn.MinWidth = 0;
                                renamedDetailsColumn.HeaderText = "";
                                renamedDetailsColumn.Width = 0;
                                renamedDetailsColumn.MaxWidth = 1;
                                renamedDetailsColumn.ReadOnly = true;
                                renamedDetailsColumn.VisibleInColumnChooser = false;
                            }
                            this.TableElement.UpdateView();                   
                        }
      
                    }
                }
            }
      
            [Browsable(true)]
            [Category("Row Details")]
            [DefaultValue(100)]
            public int DetailsRowHeight
            {
                get 
                {
                    return this.renamedDetailsRowHeight; 
                }
                set
                {
                    if (renamedDetailsRowHeight != value && useRowDetails == true)
                    {
                        renamedDetailsRowHeight = value;
                        TableElement.Update(GridUINotifyAction.Reset);
                        TableElement.UpdateView();
                    }
                }
            }
      
            [Browsable(true)]
            [Category("Row Details")]
            [DefaultValue(true)]
            public bool ShowRowDetails
            {
                get 
                
                    return this.showRowDetails; 
                }
                set
                {
                    if (useRowDetails == true)
                    
                        showRowDetails = value;
                        this.DetailsColumn.IsVisible = value;
                        TableElement.Update(GridUINotifyAction.Reset);
                        TableElement.UpdateView();               
                    }
                }
            }
      
            [Browsable(true)]
            [Category("Row Details")]
            [Description("Allows all rows to be expanded (true) or only selected row expanded (false)")]
            [DefaultValue(true)]
            public bool EnableAllExpand
            {
                get { return this.enableAllExpand; }
                set
                {
                    this.enableAllExpand = value;
                    TableElement.Update(GridUINotifyAction.Reset);
                    TableElement.UpdateView();
                }
            }
      
            [Browsable(false)]
            [Category("Row Details")]
            [DefaultValue(true)]
            public bool RowDetailsShowing
            {
                get { return this.showRowDetails; }
            }
      
            protected override void OnCreateRow(object sender, GridViewCreateRowEventArgs e)
            {
                if (useRowDetails == true)
                
                    if (object.ReferenceEquals(e.RowType, typeof(GridDataRowElement)))
                    {
                        e.RowType = typeof(RowDetailsRowElement);
                    }            
                }
                base.OnCreateRow(sender, e);
            }
        }
    }

    I have commented it, but for a reason that I'm not sure about at the moment, you should not make the "Details" column the last one in your source.

    I do hope this helps, but let me know if you have any questions
    Richard
  11. Cat
    Cat avatar
    19 posts
    Member since:
    Nov 2010

    Posted 02 Mar 2011 Link to this post

    Thank you Richard, you've gone above and beyond the call of duty on this one!

    Some things I noted from my own research:
    1. Regardless of how you set the "Details" visibility initially, that column is visible when the ArrangeCell call is made in the RowDetailsLayout class. You can check this with a breakpoint. It makes sense, because you wouldn't see anything in the details space otherwise. I've had to explicitly set this, as the InvalidateRenderColumns() and ArrangeCell() methods require this column. I think the reason it's working in your example is that you've set the grid to AutoGenerateColumns = true, but I haven't tested this yet. I'm explicitly defining the columns in my master template, and without setting the visibility to true, nothing ever renders in the details area.
    2. There appears to be a bug in the InvalidateRenderColumns() method for computing the "systemWidth". This might be why the "details" column can't be the last column referenced? I'm working through that issue right now.
    3. Finally, I was going to mention that the cell properties that do not change need to be reset in the CellFormatting handler, but it looks like you updated that in this example. :)

    Thank you for the great example though. I was just planning on leveraging the "ShowRowDetails" property to selectively hide/show the details as needed.

    Do let me know if you can confirm or refute the issues above!

  12. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 03 Mar 2011 Link to this post

    Hi Cat,

    Yes, I admit that it's not without a few issues, but perhaps we can work around them. You're right that the ArrangeCell and InvalidateRenderColumns requires the details column.

    I'm also looking at why the details column cannot be the last one. At the moment though I haven't got there.
    I've tried it with setting the columns and not auto generating them and all seems to work fine (though the details column cannot be the last one).
    Yes, the cell styles need to be reset, and it should have gone into the original sample but as you saw, it's now in the exxample I posted above.

    I'll keep looking at this for you, but in the meantime, please remember to mark helpful posts as answer.
    I'll let you know any results I find and if you have any additional questions, then please let me know. hopefully though this has given you a good idea on how to achieve your goal.
    regards,
    Richard
  13. Answer
    Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 03 Mar 2011 Link to this post

    Hi Cat,

    Ok, I've come up with a workaround so the details column can be the last one. I've re-posted all the changed files here again. It also now includes specifying the columns.

    The workaround for getting the details column to be the last (or any other) column is in GridViewRowDetailsExtended

    Designer File
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.ButtonPopulateHierarchy = new Telerik.WinControls.UI.RadButton();
            this.ButtonPopulateRowDetails = new Telerik.WinControls.UI.RadButton();
            this.gridViewRowDetailsExtended1 = new GridviewRowDetailsExtended.GridViewRowDetailsExtended();
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateHierarchy)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateRowDetails)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.gridViewRowDetailsExtended1)).BeginInit();
            this.SuspendLayout();
            // 
            // ButtonPopulateHierarchy
            // 
            this.ButtonPopulateHierarchy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.ButtonPopulateHierarchy.Location = new System.Drawing.Point(12, 480);
            this.ButtonPopulateHierarchy.Name = "ButtonPopulateHierarchy";
            this.ButtonPopulateHierarchy.Size = new System.Drawing.Size(177, 24);
            this.ButtonPopulateHierarchy.TabIndex = 1;
            this.ButtonPopulateHierarchy.Text = "Populate With Hierarchy Data";
            this.ButtonPopulateHierarchy.Click += new System.EventHandler(this.ButtonPopulateHierarchy_Click);
            // 
            // ButtonPopulateRowDetails
            // 
            this.ButtonPopulateRowDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.ButtonPopulateRowDetails.Location = new System.Drawing.Point(204, 480);
            this.ButtonPopulateRowDetails.Name = "ButtonPopulateRowDetails";
            this.ButtonPopulateRowDetails.Size = new System.Drawing.Size(177, 24);
            this.ButtonPopulateRowDetails.TabIndex = 2;
            this.ButtonPopulateRowDetails.Text = "Populate With Row Details Data";
            this.ButtonPopulateRowDetails.Click += new System.EventHandler(this.ButtonPopulateRowDetails_Click);
            // 
            // gridViewRowDetailsExtended1
            // 
            this.gridViewRowDetailsExtended1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.gridViewRowDetailsExtended1.DetailsColumn = null;
            this.gridViewRowDetailsExtended1.Location = new System.Drawing.Point(12, 12);
            this.gridViewRowDetailsExtended1.Name = "gridViewRowDetailsExtended1";
            this.gridViewRowDetailsExtended1.Size = new System.Drawing.Size(522, 453);
            this.gridViewRowDetailsExtended1.TabIndex = 0;
            this.gridViewRowDetailsExtended1.Text = "gridViewRowDetailsExtended1";
            this.gridViewRowDetailsExtended1.CellFormatting += new Telerik.WinControls.UI.CellFormattingEventHandler(this.gridViewRowDetailsExtended1_CellFormatting);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(543, 516);
            this.Controls.Add(this.ButtonPopulateRowDetails);
            this.Controls.Add(this.ButtonPopulateHierarchy);
            this.Controls.Add(this.gridViewRowDetailsExtended1);
            this.Name = "Form1";
            this.Text = "Form1";
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateHierarchy)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.ButtonPopulateRowDetails)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.gridViewRowDetailsExtended1)).EndInit();
            this.ResumeLayout(false);
        }
        #endregion
        private GridviewRowDetailsExtended.GridViewRowDetailsExtended gridViewRowDetailsExtended1;
        private Telerik.WinControls.UI.RadButton ButtonPopulateHierarchy;
        private Telerik.WinControls.UI.RadButton ButtonPopulateRowDetails;
    }

    Form1.cs
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using Telerik.WinControls.UI;
      
      
        public partial class Form1 : Form
        {
            BindingList<Person> people = new BindingList<Person>();
            BindingList<Child> children = new BindingList<Child>();
      
            public Form1()
            {
                InitializeComponent();
                // set defaults
                this.gridViewRowDetailsExtended1.ReadOnly = true;
                this.gridViewRowDetailsExtended1.ShowFilteringRow = false;
                this.gridViewRowDetailsExtended1.ShowGroupPanel = false;
                this.gridViewRowDetailsExtended1.AutoGenerateColumns = false
            }
      
            private void ButtonPopulateHierarchy_Click(object sender, EventArgs e)
            {
                // reset grid
                this.gridViewRowDetailsExtended1.DataSource = null;
                this.gridViewRowDetailsExtended1.Columns.Clear();
                PopulatePeople();
                PopulateChildren();
      
                GridViewDecimalColumn idColumn = new GridViewDecimalColumn("Id");
                idColumn.HeaderText = "Id";
                idColumn.Name = "Id";
                GridViewTextBoxColumn nameColumn = new GridViewTextBoxColumn("Name");
                nameColumn.HeaderText = "Name";
                nameColumn.Name = "Name";
                GridViewTextBoxColumn titleColumn = new GridViewTextBoxColumn("Title");
                titleColumn.HeaderText = "Title";
                titleColumn.Name = "Title";
                GridViewDateTimeColumn dateColumn = new GridViewDateTimeColumn("Date");
                dateColumn.HeaderText = "Date";
                dateColumn.Name = "Date";
                GridViewTextBoxColumn detailsColumn = new GridViewTextBoxColumn("Details");
                detailsColumn.HeaderText = "Details";
                detailsColumn.Name = "Details";
                GridViewTextBoxColumn commentsColumn = new GridViewTextBoxColumn("Comments");
                commentsColumn.HeaderText = "Comments";
                commentsColumn.Name = "Comments";
                this.gridViewRowDetailsExtended1.Columns.AddRange(idColumn, nameColumn, titleColumn, dateColumn, commentsColumn, detailsColumn);
      
                // give a data source
                this.gridViewRowDetailsExtended1.DataSource = people;
                this.gridViewRowDetailsExtended1.Columns["Details"].IsVisible = true;
                // new: use row details false
                this.gridViewRowDetailsExtended1.UseRowDetails = false;
                this.gridViewRowDetailsExtended1.ShowRowDetails = false;
                this.gridViewRowDetailsExtended1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill;
      
                // hierarchy stuff - the child template
                GridViewTemplate childTemplate = new GridViewTemplate();
                childTemplate.DataSource = children;
                this.gridViewRowDetailsExtended1.MasterTemplate.Templates.Add(childTemplate);
      
                // set up a relation
                GridViewRelation relation = new GridViewRelation(this.gridViewRowDetailsExtended1.MasterTemplate, childTemplate);
                relation.RelationName = "ParentChildRelation";
                relation.ParentColumnNames.Add("Id");
                relation.ChildColumnNames.Add("ParentId");
                this.gridViewRowDetailsExtended1.Relations.Add(relation);
      
                // best fit the columns
                foreach (GridViewDataColumn column in this.gridViewRowDetailsExtended1.Columns)
                { column.BestFit(); }
            }
      
            private void ButtonPopulateRowDetails_Click(object sender, EventArgs e)
            {
                // reset grid
                this.gridViewRowDetailsExtended1.Relations.Clear();
                this.gridViewRowDetailsExtended1.Templates.Clear();
                this.gridViewRowDetailsExtended1.Columns.Clear();
                this.gridViewRowDetailsExtended1.DataSource = null;
                PopulatePeople();
      
                GridViewDecimalColumn idColumn = new GridViewDecimalColumn("Id");
                idColumn.HeaderText = "Id";
                idColumn.Name = "Id";
                GridViewTextBoxColumn nameColumn = new GridViewTextBoxColumn("Name");
                nameColumn.HeaderText = "Name";
                nameColumn.Name = "Name";
                GridViewTextBoxColumn titleColumn = new GridViewTextBoxColumn("Title");
                titleColumn.HeaderText = "Title";
                titleColumn.Name = "Title";
                GridViewDateTimeColumn dateColumn = new GridViewDateTimeColumn("Date");
                dateColumn.HeaderText = "Date";
                dateColumn.Name = "Date";
                GridViewTextBoxColumn detailsColumn = new GridViewTextBoxColumn("Details");
                detailsColumn.HeaderText = "Details";
                detailsColumn.Name = "Details";
                GridViewTextBoxColumn commentsColumn = new GridViewTextBoxColumn("Comments");
                commentsColumn.HeaderText = "Comments";
                commentsColumn.Name = "Comments";
                this.gridViewRowDetailsExtended1.Columns.AddRange(idColumn, nameColumn, titleColumn, dateColumn, commentsColumn, detailsColumn);
      
      
                // new: use row details true
                this.gridViewRowDetailsExtended1.UseRowDetails = true;
                this.gridViewRowDetailsExtended1.Columns["Details"].IsVisible = false;
                // give it the row details column
                this.gridViewRowDetailsExtended1.DetailsColumn = this.gridViewRowDetailsExtended1.Columns["Details"];
                // show the row details
                this.gridViewRowDetailsExtended1.EnableAllExpand = false;
                this.gridViewRowDetailsExtended1.ShowRowDetails = true;
      
                this.gridViewRowDetailsExtended1.AutoSizeColumnsMode = Telerik.WinControls.UI.GridViewAutoSizeColumnsMode.Fill;
                // so we can add html to the row details area
                this.gridViewRowDetailsExtended1.Columns["Details"].DisableHTMLRendering = false;
      
                // data source
                this.gridViewRowDetailsExtended1.DataSource = people;
      
                // best fit the columns
                foreach (GridViewDataColumn column in this.gridViewRowDetailsExtended1.Columns)
                {
                    if (column.Name != "Details")
                    {column.BestFit();  }
                }
            }
      
            private void PopulatePeople()
            {
                people.Clear(); 
                people.Add(new Person(1,"Richard", "Mr", DateTime.Now, "WinForms Developer", "Here are some details about Richard"));
                people.Add(new Person(2,"Chris", "Mr", DateTime.Now, "Operations Manager", "Here are some details about Chris"));
                people.Add(new Person(3,"Leisl", "Mrs", DateTime.Now, "Administative Assistant", "Here are some details about Leisl"));
                people.Add(new Person(4,"Chris", "Mr", DateTime.Now, "Cleaner", "Here are some details about Chris"));
                people.Add(new Person(5,"Peter", "Mr", DateTime.Now, "WinForms Developer", "Here are some details about Peter"));
                people.Add(new Person(6,"Ester", "Miss", DateTime.Now, "School Teacher", "Here are some details about Ester"));
            }
      
            private void PopulateChildren()
            {
                children.Clear();
                children.Add(new Child(1, 1, "Javier"));
                children.Add(new Child(2, 2, "Jamie"));
                children.Add(new Child(3, 2, "Max"));
                children.Add(new Child(4, 5, "Zack"));
            }
      
            private void gridViewRowDetailsExtended1_CellFormatting(object sender, Telerik.WinControls.UI.CellFormattingEventArgs e)
            {
                // if it's a row details grid 
                if (this.gridViewRowDetailsExtended1.Relations.Count == 0) 
                
                    // and if its the current row and rowDetails column
                    if (e.CellElement.RowInfo.IsCurrent && e.CellElement.ColumnInfo == this.gridViewRowDetailsExtended1.DetailsColumn)
                    {
                        // set some html and style
                        e.CellElement.DrawFill = true;
                        e.CellElement.GradientStyle = Telerik.WinControls.GradientStyles.Solid;
                        e.CellElement.BackColor = Color.LightBlue;
                        e.CellElement.Padding = new Padding(10);
                        e.CellElement.Text = "<html>" + e.CellElement.Text.Replace("Here", "<strong>Here</strong>") + "</html>";
                    }
                    else
                    {
                        // otherwise reset for UI Virtualization
                        e.CellElement.ResetValue(LightVisualElement.DrawFillProperty, Telerik.WinControls.ValueResetFlags.Local);
                        e.CellElement.ResetValue(LightVisualElement.GradientStyleProperty, Telerik.WinControls.ValueResetFlags.Local);
                        e.CellElement.ResetValue(LightVisualElement.BackColorProperty, Telerik.WinControls.ValueResetFlags.Local);
                        e.CellElement.ResetValue(LightVisualElement.PaddingProperty, Telerik.WinControls.ValueResetFlags.Local);
                    }            
                }
      
      
            }
        }
      
        /// <summary>
        /// Note: Currently, whatever you use for Row Details
        /// cannot be the last column. In this case "Details" is one but last
        /// </summary>
        public class Person
        {
            public Person(int id, string name, string title, DateTime date, string comments, string details)
            {
                this.Id = id;
                this.Name = name;
                this.Title = title; 
                this.Date = date;
                this.Comments = comments;
                this.Details = details;
            }
      
            public int Id
            { get; set; }
      
            public string Name
            {get; set;}
      
            public string Title
            {get; set;}
      
            public DateTime Date
            {get; set;}
      
            public string Details
            { get; set; }
      
            public string Comments
            {get; set;}
      
        }
      
        public class Child
        {
            public Child(int id, int parentId, string name)
            {
                this.Id = id;
                this.ParentId = parentId;
                this.Name = name;
            }
      
            public int Id
            { get; set; }
      
            public int ParentId
            { get; set; }
      
            public string Name
            { get; set; }
      
        }

    GridViewRowDetailsExtended.cs
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Telerik.WinControls.UI;
    using System.ComponentModel;
      
    namespace GridviewRowDetailsExtended
    {
        public class GridViewRowDetailsExtended : RadGridView
        {
            private GridViewDataColumn renamedDetailsColumn;
            private int renamedDetailsRowHeight = 100;
            private bool showRowDetails = true;
            private bool enableAllExpand = true;
            private bool useRowDetails = true;
      
            public GridViewRowDetailsExtended()
            {
                this.GridBehavior = new RowDetailsBehavior();
                this.ViewDefinition = new RowDetailsViewDefinition();
            }
      
            public override string ThemeClassName
            {
                get { return typeof(RadGridView).FullName; }
                set { }
            }
      
            public bool UseRowDetails
            {
                get { return useRowDetails; }
                set { useRowDetails = value; }
            }
      
      
            [Browsable(false)]
            [Category("Row Details")]
            public GridViewDataColumn DetailsColumn
            {
                get { return this.renamedDetailsColumn; }
      
                set
                {
                    if (!object.ReferenceEquals(renamedDetailsColumn, value))
                    {
                        if (useRowDetails == true)
                        {
                            renamedDetailsColumn = value;
                            if (renamedDetailsColumn != null)
                            {
                                renamedDetailsColumn.MinWidth = 0;
                                renamedDetailsColumn.HeaderText = "";
                                renamedDetailsColumn.Width = 0;
                                renamedDetailsColumn.ReadOnly = true;
                                renamedDetailsColumn.VisibleInColumnChooser = false;
      
                                if (renamedDetailsColumn.Index != this.ColumnCount - 1)
                                {renamedDetailsColumn.MaxWidth = 1;}
                                else
                                {renamedDetailsColumn.MaxWidth = 2;}
                            }
                            this.TableElement.UpdateView();
                        }
      
                    }
                }
            }
      
            [Browsable(true)]
            [Category("Row Details")]
            [DefaultValue(100)]
            public int DetailsRowHeight
            {
                get 
                {
                    return this.renamedDetailsRowHeight; 
                }
                set
                {
                    if (renamedDetailsRowHeight != value && useRowDetails == true)
                    {
                        renamedDetailsRowHeight = value;
                        TableElement.Update(GridUINotifyAction.Reset);
                        TableElement.UpdateView();
                    }
                }
            }
      
            [Browsable(true)]
            [Category("Row Details")]
            [DefaultValue(true)]
            public bool ShowRowDetails
            {
                get 
                
                    return this.showRowDetails; 
                }
                set
                {
                    if (useRowDetails == true)
                    
                        showRowDetails = value;
                        this.DetailsColumn.IsVisible = value;
                        TableElement.Update(GridUINotifyAction.Reset);
                        TableElement.UpdateView();               
                    }
                }
            }
      
            [Browsable(true)]
            [Category("Row Details")]
            [Description("Allows all rows to be expanded (true) or only selected row expanded (false)")]
            [DefaultValue(true)]
            public bool EnableAllExpand
            {
                get { return this.enableAllExpand; }
                set
                {
                    this.enableAllExpand = value;
                    TableElement.Update(GridUINotifyAction.Reset);
                    TableElement.UpdateView();
                }
            }
      
            [Browsable(false)]
            [Category("Row Details")]
            [DefaultValue(true)]
            public bool RowDetailsShowing
            {
                get { return this.showRowDetails; }
            }
      
            protected override void OnCreateRow(object sender, GridViewCreateRowEventArgs e)
            {
                if (useRowDetails == true)
                
                    if (object.ReferenceEquals(e.RowType, typeof(GridDataRowElement)))
                    {
                        e.RowType = typeof(RowDetailsRowElement);
                    }            
                }
                base.OnCreateRow(sender, e);
            }
        }
    }

    i hope that helps, but if you have any comments or questions, please let me know
    Thanks
    Richard
  14. Cat
    Cat avatar
    19 posts
    Member since:
    Nov 2010

    Posted 03 Mar 2011 Link to this post

    Hi Richard!
    Thanks again for all your hard work! You've actually been instrumental in keeping my project on shedule and meeting requirements, so I can't thank you enough. I hope Telerik recognises all your hard work!

    I've marked two of your replies as an answer, so hopefully that will help win you some points. I thought I had marked one as an answer earlier, but apparently something happened as I had to do it again.

    I believe I have everything working now with your help, so consider this subject closed. Whew! :)

    -Andy
  15. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 03 Mar 2011 Link to this post

    Hi Andy,

    That's really good news! - I'm very pleased that I was able to help.
    If anything else comes up, please let me know and I'll do my best to assist.
    All the best
    Richard
  16. vinson
    vinson avatar
    3 posts
    Member since:
    Feb 2017

    Posted 26 Feb 2017 Link to this post

    Hi Richard, 

    Your grid view is awesome, however, there is one issue I am currently experiencing which is I cannot get the selected cell value from the child grid view. I have no problem with retrieving selected cell value from the parent grid view. 

    I want user also able to delete a row from the child grid view after the delete button is pressed. But it seems there is a way I can register the event handler for the child grid view. 

    Please help

  17. Dess | Tech Support Engineer, Sr.
    Admin
    Dess | Tech Support Engineer, Sr.  avatar
    4086 posts

    Posted 28 Feb 2017 Link to this post

    Hello Vinson,

    Thank you for writing.  

    Your question has already been answered in the other thread that you have opened on the same topic. Here is the relevant link to the forum thread: http://www.telerik.com/forums/delete-record-at-child-view-on-grid-view

    I hope this information helps. Should you have further questions I would be glad to help.

    Regards,
    Dess
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Back to Top