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

How Do I Edit a Child Row and Update the Parent Row?

24 Answers 918 Views
GridView
This is a migrated thread and some comments may be shown as answers.
AaronP
Top achievements
Rank 1
AaronP asked on 14 Oct 2010, 05:04 PM
Hi,

I'm using version 2010.2.10.914 and a databounded hierarchy gridview.  What I need to do is to be able to edit a quantity in a child row and then based on the new value update the parent row cost.  An overview of what I'm trying to do:

Parent row has 3 columns: Name, Qty, and Cost.  The cost is the sum on the parts in the child row and when the Qty is changed then it affects the child row Qty and Cost. 

The child row has 3 columns: Part, Qty, Cost. Now what I'm trying to do is change the Qty in the child row and adjust the child cost and the parent cost.  So in the CellEndEdit event, I update the child row, but when I add this line:

e.Row.ViewInfo.ParentRow.Cells["Cost"].Value 
            = (decimal)e.Row.ViewInfo.ParentRow.Cells["Cost"].Value   + newChildCost - oldChildCost;

I get a NullReferenceException "Object reference not set to an instance of an object." when the CellEndEdit event method ends (not on the added line).  When I step thru the code, everything seems to be ok until the end of the method.

Any idea why the error is occurring, is there a better way to synchronize values from the child rows to parent rows? 

Thank you,
Aaron

24 Answers, 1 is accepted

Sort by
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 06:32 PM
Hello AaronP,

Try it like this:
var row = e.Row.Parent as GridViewRowInfo;
if (row != null)
{
    row.Cells["Cost"].Value = (int)row.Cells["Cost"].Value + newChildCost - oldChildCost;
}

The ParentRow property is obsolete in the latest release Q2 2010 SP2 ...914, and if you don't have the latest version i would suggest updating to the latest version, there are a series of bug fixes and improvements

Hope this helps, if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 06:45 PM
Hello Emanuel,

i originally had tried the following:

GridViewRowInfo row = e.Row.Parent as GridViewRowInfo;
 //and
GridViewHierarchyRowInfo row = e.Row.Parent as GridViewHierarchyRowInfo;

but I was getting the same error.  I used something like the original code in my post in an older version of the control whiched worked and that's why I posted that code.  I just tried your suggestion (setting the row variable using the var keyword and added the if statement), but it still did not work. 

I am on the current 914 version.

Thanks for looking at this,
Aaron
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 06:50 PM
Hello again,

Originally, i saw your post and tried something another way, please take a look at this example and tell me if this is working for you:
namespace TestGridHierachy___ChangeParentOnChild
{
    using System.Collections.Generic;
    using System.Windows.Forms;
    using Telerik.WinControls.UI;
 
    public partial class Form1 : Form
    {
        List<Person> People = new List<Person>();
 
        List<Car> Cars = new List<Car>();
        private RadGridView radGridView1 = new RadGridView();
         
        public Form1()
        {
            InitializeComponent();
 
            this.radGridView1.Dock = DockStyle.Fill;
            this.Controls.Add(radGridView1);
            this.radGridView1.ReadOnly = false;
            this.radGridView1.AllowAddNewRow = true;
            radGridView1.MasterTemplate.Columns.Add(new GridViewDateTimeColumn("TestColumn"));
 
            this.radGridView1.AutoGenerateHierarchy = true;
            // load primary data source
            People.Add(new Person(1, 101, "Bob", 42));
            People.Add(new Person(1, 102, "Rob", 88));
            People.Add(new Person(3, 103, "Eric", 22));
            this.radGridView1.DataSource = People;
            this.radGridView1.BestFitColumns();
 
            // Now create first relation
            GridViewTemplate carTemplate = new GridViewTemplate();
            Cars.Add(new Car(101, "Ford", 100));
            Cars.Add(new Car(101, "BMW", 104));
            Cars.Add(new Car(103, "Mazda", 100));
            Cars.Add(new Car(104, "Merc", 100));
            Cars.Add(new Car(105, "Honda", 100));
            carTemplate.DataSource = Cars;
 
            GridViewRelation carsRelation = new GridViewRelation(this.radGridView1.MasterTemplate);
            carsRelation.ChildTemplate = carTemplate;
            carsRelation.RelationName = "ParentChild";
            carsRelation.ParentColumnNames.Add("ID2");
            carsRelation.ChildColumnNames.Add("ID");
            this.radGridView1.Relations.Add(carsRelation);
            carTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
            carTemplate.BestFitColumns();
            carTemplate.Caption = "Cars";
 
            this.radGridView1.MasterTemplate.Templates.Add(carTemplate);
 
            radGridView1.CellValueChanged += new GridViewCellEventHandler(radGridView1_CellValueChanged);
            radGridView1.MasterTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
        }
 
        void radGridView1_CellValueChanged(object sender, GridViewCellEventArgs e)
        {
            if (radGridView1.Templates[0].Rows.Contains(e.Row))
            {
                var row = e.Row.Parent as GridViewRowInfo;
                 
                var price = 0;
                foreach (var childRow in row.ChildRows)
                {
                    price += (int)childRow.Cells["Price"].Value;
                }
 
                row.Cells["Price"].Value = price;
            }
        }
    }
 
    public class Person
    {
        public int ID
        {
            get;
            set;
        }
 
        public int ID2
        {
            get;
            set;
        }
 
        public string Name
        {
            get;
            set;
        }
 
        public int Price
        {
            get;
            set;
        }
 
        public Person(int id, int id2, string name, int price)
        {
            ID = id;
            ID2 = id2;
            Name = name;
            Price = price;
        }
    }
 
    public class Car
    {
        public int ID
        {
            get;
            set;
        }
 
        public string Model
        {
            get;
            set;
        }
 
        public int Price { get; set; }
 
        public Car(int id, string model, int price)
        {
            ID = id;
            Model = model;
            Price = price;
        }
    }
}

Best Regards,
Emanuel Varga
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 07:05 PM
HI Emanuel,

I was able to run you example and it worked.  I'll try using CellValueChanged event it in my code and see what happens.

Thank you!
Aaron
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 07:34 PM
Please let me know how it turned up, and please, let me know if i can do anything else to help.

Best Regards,
Emanuel Varga
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 09:28 PM
I made a few changes and it's still not working.  I'm currently trying to see if I can reproduce the issue with test code I can sent in full.

Do you have any other suggestions at this time?

Thank you,
Aaron
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 09:31 PM
Are you also saving the data to the db / refreshing data from the db?
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 09:39 PM
Not yet.  I have been trying to make sure all the data changes I want the client to do is coded first.  I do grab data (placed in a Dataset) from SQL Server to initially populate the grid. 
0
Accepted
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 09:43 PM
This usually happens when a grid update / data source update is being called from somewhere outside the cell.
I will give you something to try, to see if it's the same result, but I'm almost certain it will work (but i don't like it...)

Please put this at the final line of cell value changed (please check that the timer used is Windows.Forms.Timer)
var timer = new Timer() { Interval = 10 };
timer.Tick += delegate
    {
        timer.Stop();
        row.Cells["Cost"].Value = (int)row.Cells["Cost"].Value + newChildCost - oldChildCost;
    };
timer.Start();

Again, for the record, i know it is stupid, but please humor me and tell me if it's working or not.

Best Regards,
Emanuel Varga
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 09:51 PM
I added the timer code and now it's not crashing and is updating the parent row.  So what should I be looking for to fix the code without a timer.

Thank you for help,
Aaron
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 09:56 PM
Yes, i was afraid of that, The change in the parent row is causing a change in the child rows or it is just calling a refresh, which, because the edit operation is not complete is throwing a Null Reference....

The simplest solution would be to use Bussiness objects implementing INotifyPropertyChanged, and a BindingList, that would assure that changes will be sent to the grid in a good way. With that instead of changing the values to the grid you could just say var something = row.DataBoundItem as SomeObject and set the value of that object, it would be cleaner and nicer.

But it is your call, if you want to continue with DataSets and DataTable, please let me know and i will try to find a way...

Best Regards,
Emanuel Varga
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 10:10 PM
I've ran into this problem before... and i tend to think it's a bug, and it's very easy to prove, just call a refresh on the grid in the CellValueChanged event (when you are editing a child row)and it will throw a NullReference Exception....

As an even more "temporary" fix, if there is such a thing, try collapsing the parent before you change the value for the Price it should work like this also, like:
row.IsExpanded = false;

Please let me know of the result.
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 10:25 PM
Emanuel,

Thank you for your help.  I might be able to rearrange my code to use business objects, but I think if you can come up with a good solution for the DataSet / DataTable users then that could help others.  At least for now I have a work around with the Timer solution. 

The row.IsExpanded = false works only if I do not have any other parent row expanded.  I tried the refresh() method in your test code you gave me earlier and it caused the Nullreference error.

Thank you very much for the help,
Aaron
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 10:30 PM
I know, i told you it will do that, but this will happen only when the change you are making is affecting other ChildRows, and this is the weird thing, the price change in the parent should not affect any child row, or should it?
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 10:47 PM
There is a Qty column in the parent row a user can change which will adjust the child row qty and cost columns.  That bit has been working for awhile now.  As for the parent price change, this does not affect child rows, but I'll double check my code and verify.

Thank you,
Aaron
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 10:51 PM
When the parent row affects the child rows it's ok, because the change is in just one direction, but when the child row affects the parent row and the parent row affects the child row it's a very ugly circle...
But i still think it's a bug somewhere...

Please let me know if there is anything else i can do to help.

Best Regards,
Emanuel Varga
0
AaronP
Top achievements
Rank 1
answered on 14 Oct 2010, 10:53 PM
Actually one quick question, when you say "But i still think it's a bug somewhere" are you referring to my code or within the gridview control?
0
Emanuel Varga
Top achievements
Rank 1
answered on 14 Oct 2010, 11:09 PM
In the grid view, on refresh while child cell is editing, like i said before, I'm assuming that there is some validation that has to run at the end of the editing process and this is causing the exception...

I'll keep trying to find a better solution, until then i hope that workaround is working fine, if it's a bug on their side, I'm almost certain that they will fix it in Q3 which is due in November.

Best Regards, and again, please let me know if there is anything else i can do to help,
Emanuel Varga
0
Jack
Telerik team
answered on 20 Oct 2010, 11:08 AM
Hi Aaron,

As Emanuel suggested you have to use the CellValueChanged event in this case. I made a small test using the following code snippet and everything seems to work correctly:
void radGridView1_CellValueChanged(object sender, GridViewCellEventArgs e)
{
    if (e.Row.ViewInfo.ParentRow != null && e.Column.Name == "Value")
    {
        e.Row.ViewInfo.ParentRow.Cells["Value"].Value = e.Row.Cells["Value"].Value;
    }
}

Could you please confirm that this code works for you? If not, please open a new support ticket and send me your application and I will try to find the best option.

The exception occurs because of the asynchronous nature of the layout system used in RadGridView and the TPF. It is possible that your change causes a refresh which changes the element tree. You do not have to use timers, instead you can call the Application.DoEvents or RootElement.UpdateLayout methods.

I hope this helps. If you have further questions, please write back.
 
Sincerely yours,
Jack
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
AaronP
Top achievements
Rank 1
answered on 20 Oct 2010, 04:06 PM
Hi Jack,

I tried your code and it did not work for me. I also played around with Application.DoEvents and RootElement.UpdateLayout but it still would get the same error.  I'll try to put a project together that I can give you to show the problem and if I can duplicate the issue I'll open a support ticket.

Thank you,
Aaron
0
Jack
Telerik team
answered on 26 Oct 2010, 08:53 AM
Hello AaronP,

Thank you for writing back. I am looking forward to your project. If there is something else we can assist you with, please do not hesitate to contact us.

All the best,
Jack
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Bill Battaglia
Top achievements
Rank 1
answered on 01 Feb 2011, 07:18 PM
I am updating the parent row and I am also getting the NullReferenceException, so kindly let me know how can we fix this issue? Its a major problem.
0
AaronP
Top achievements
Rank 1
answered on 02 Feb 2011, 05:21 PM
Hi Bill,

I would try two options:
1)  If you can upgrade to Telerik version 2010 Q3 or 2010 Q3 SP1, then that might work.  Since I updated to 2010 Q3 my problem has been resolved.
2)  If you can't upgrade then try similar code in the event you are trying to update the parent with what Emanuel Varga posted:

var timer = new Timer() { Interval = 10 };
timer.Tick += delegate
    {
        timer.Stop();
        row.Cells["Cost"].Value = (int)row.Cells["Cost"].Value + newChildCost - oldChildCost;
    };
timer.Start();

You may need to change the interval a bit (if I remember I bumped it 50). 
I hope this helps,
Aaron
0
Jack
Telerik team
answered on 09 Feb 2011, 10:01 AM
@Aaron, thank you for your suggestion.

Bill, please consider updating your version to the latest one. If the issue continues to appear, please send me your application and I will try to locate the issue.

I am looking forward to your reply.

Regards,
Tsvetan Raykov
the Telerik team
Q3’10 SP1 of RadControls for WinForms is available for download; also available is the Q1'11 Roadmap for Telerik Windows Forms controls.
Tags
GridView
Asked by
AaronP
Top achievements
Rank 1
Answers by
Emanuel Varga
Top achievements
Rank 1
AaronP
Top achievements
Rank 1
Jack
Telerik team
Bill Battaglia
Top achievements
Rank 1
Share this question
or