Store and restore IsExpanded in self-referencing hierarchy grid

6 posts, 0 answers
  1. Roman
    Roman avatar
    15 posts
    Member since:
    Jan 2011

    Posted 25 Jul Link to this post

    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?

  2. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 26 Jul Link to this post

    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 property keep in an appropriate data structure which are 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.
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Roman
    Roman avatar
    15 posts
    Member since:
    Jan 2011

    Posted 26 Jul Link to this post

    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.

  5. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 26 Jul Link to this post

    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.IsExpanded 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.
  6. Roman
    Roman avatar
    15 posts
    Member since:
    Jan 2011

    Posted 26 Jul in reply to Dess Link to this post

    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)?

  7. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 27 Jul Link to this post

    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.
Back to Top
UI for WinForms is Visual Studio 2017 Ready