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

Store and restore IsExpanded in self-referencing hierarchy grid

5 Answers 85 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Roman
Top achievements
Rank 1
Roman asked on 25 Jul 2016, 05:14 PM

Hello,

How can I remember and restore IsExpanded state in bound self-referencing hierarchy grid when source collection (BindingList<T>) is updated? 

Basically I see 2 solutions, remember the rows state before update and restore it after, or make IsExpanded property in bound object and update it accordingly.

The problem with first approach is that I don't know, which events I should handle to remember and restore IsExpanded state for all updates.

For the second approach I was able to handle RowFormatting event and set initial expanded state for the row. But then I was not able to find a correct event to update IsExpanded value in corresponding object when row is expanded or collapsed by user.

Could someone help?

5 Answers, 1 is accepted

Sort by
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 26 Jul 2016, 08:49 AM
Hello Roman,

Thank you for writing. 

I have prepared a sample code snippet demonstrating that when updating a property in the DataBoundItem doesn't collapse the expanded rows: 
BindingList<Student> collectionOfStudents = new BindingList<Student>();
BindingList<School> collectionOfSchools = new BindingList<School>();
 
public Form1()
{
    InitializeComponent();
 
    collectionOfStudents.Add(new Student(1, "Peter", "D-",2));
    collectionOfStudents.Add(new Student(2, "Antony", "B+",1));
    collectionOfStudents.Add(new Student(3, "David", "A-",1));
    collectionOfStudents.Add(new Student(4, "John", "D-",2));
    collectionOfSchools.Add(new School("Schrool 1",1));
    collectionOfSchools.Add(new School("Schrool 2",2));
 
    radGridView1.DataSource = collectionOfSchools;
    radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
    GridViewTemplate template = new GridViewTemplate();
    template.DataSource = collectionOfStudents;
    template.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
    radGridView1.MasterTemplate.Templates.Add(template);
 
    GridViewRelation relation = new GridViewRelation(radGridView1.MasterTemplate);
    relation.ChildTemplate = template;
    relation.RelationName = "SchoolsStudents";
    relation.ParentColumnNames.Add("Id");
    relation.ChildColumnNames.Add("SchoolId");
    radGridView1.Relations.Add(relation);
}
 
public class School: System.ComponentModel.INotifyPropertyChanged
{
    string _name;
    int _id;
     
    public School(string name, int id)
    {
        this._name = name;
        this._id = id;
    }
 
    public string Name
    {
        get
        {
            return this._name;
        }
        set
        {
            this._name = value;
            OnPropertyChanged("Name");
        }
    }
 
    public int Id
    {
        get
        {
            return this._id;
        }
        set
        {
            this._id = value;
            OnPropertyChanged("Id");
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
 
public class Student : System.ComponentModel.INotifyPropertyChanged
{
    int m_id;
    string m_name;
    string m_grade;
    int school_id;
     
    public event PropertyChangedEventHandler PropertyChanged;
 
    public Student(int m_id, string m_name, string m_grade, int s_id)
    {
        this.m_id = m_id;
        this.m_name = m_name;
        this.m_grade = m_grade;
        this.school_id = s_id;
    }
 
    public int Id
    {
        get
        {
            return m_id;
        }
        set
        {
            if (this.m_id != value)
            {
                this.m_id = value;
                OnPropertyChanged("Id");
            }
        }
    }
 
    public string Name
    {
        get
        {
            return m_name;
        }
        set
        {
            if (this.m_name != value)
            {
                this.m_name = value;
                OnPropertyChanged("Name");
            }
        }
    }
 
    public string Grade
    {
        get
        {
            return m_grade;
        }
        set
        {
            if (this.m_grade != value)
            {
                this.m_grade = value;
                OnPropertyChanged("Grade");
            }
        }
    }
 
    public int SchoolId
    {
        get
        {
            return this.school_id;
        }
        set
        {
            this.school_id = value;
            OnPropertyChanged("SchoolId");
        }
    }
 
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
 
private void radButton1_Click(object sender, EventArgs e)
{
    collectionOfStudents[1].Name = "Name" + DateTime.Now.ToLongTimeString();
}

The following help article demonstrates how to reflect custom object changes in RadGridView: http://docs.telerik.com/devtools/winforms/gridview/populating-with-data/reflecting-custom-object-changes-in-rgv

However, if you reset the DataSource property of RadGridView, before setting the keep in an appropriate data structure which the expanded rows and restore them after that.

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

Regards,
Dess
Telerik by Progress
Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
0
Roman
Top achievements
Rank 1
answered on 26 Jul 2016, 09:50 AM

Hello Dess,

That I need to achieve is something like a binding of IsExpanded row's property to a similar business property of the bound row object. I.e. when user expand or collepse a row from the grid, corresponding IsExpanded property is changed in business object. And vice versa, if business property IsExpanded is changed row should reflect this change. In this case I don't need to bother of collection updates, because each row will have the state of its underlying item.

So far I have a handler of RowFormatting where I set row's IsExpanded property to corresponding value. But which event is fired when user expand or collapse a row in the grid? I was not able to find it, so I don't know how to update business object's property when UI is updated by user. Also it is not clear how make UI to update in case business onject's IsExpanded property is changed in code.

I am not strong in WinForms, I worked with Telerik Silverlight controls before, where this "problem" is not a problem at all. So I just don't know if there a way in WinForms to really bind row's IsExpanded to business object IsExpanded.

0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 26 Jul 2016, 11:16 AM
Hello Roman,

Thank you for writing back. 

You can use the RadGridView.ChildViewExpanded event to handle when the user expands or collapses a row and update the DataBoundItem. As to the question about updating the GridViewDataRowInfo. property when the DataBoundItem is updated, you can subscribe to the BindingList<T>.ListChanged event and manage the expanded state accordingly:
collectionOfSchools.ListChanged+=collectionOfSchools_ListChanged;

private void collectionOfSchools_ListChanged(object sender, ListChangedEventArgs e)
{
    if (e.ListChangedType == ListChangedType.ItemChanged)
    {
        this.radGridView1.Rows[e.NewIndex].IsExpanded = collectionOfSchools[e.NewIndex].IsActive;
    }
}

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

Regards,
Dess
Telerik by Progress
Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
0
Roman
Top achievements
Rank 1
answered on 26 Jul 2016, 11:30 AM

Thanks a lot, Dess, this is really help.

But is this really that simple to find a matching row by index from BindingList? Even if row is out of view because of scroll position or because some of its parent is collapsed (I have self-referencing hierarchy grid)?

0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 27 Jul 2016, 12:13 PM
Hello Roman,

Thank you for writing back. 

The provided code snippet just illustrates a sample approach and it may not cover all possible cases. When using self-referencing hierarchy, you should find the corresponding record in the BindingList considering a unique field in GridViewDataRowInfo, e.g. "Id". Thus, by the NewIndex, you can get the grid row and extract the necessary unique information by which you can traverse the DataSource collection and update the relevant field accordingly. 

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

Regards,
Dess
Telerik by Progress
Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
Tags
GridView
Asked by
Roman
Top achievements
Rank 1
Answers by
Dess | Tech Support Engineer, Principal
Telerik team
Roman
Top achievements
Rank 1
Share this question
or