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

Update ObservableCollection

12 Answers 1301 Views
GridView
This is a migrated thread and some comments may be shown as answers.
konrad
Top achievements
Rank 1
konrad asked on 25 Jul 2018, 12:03 PM
I am using ObservableCollection as a source. Class with item have INotifyPropertyChanged implemented. Also on setting value to specific prop i forcing update by OnPropertyChanged().

The problem is i see changed value only after selecting different cell or scrolling grid. It seams like grid is taking good new value of the cell when need to redraw.

How to force visible part of the grid just after list modification?

I try to use MasterTemplate.Refresh(); but it reset scroll position.

As workaround i am InvalidateRow() on each modified rows, but i think it is not proper solution.

What is more have GridViewTemplate and GridViewRelation implemented to hierarchical grid for each row (one level), and i don't know how to update cells on those grids expanded on screen?

I did not have this problem with BindingList.

12 Answers, 1 is accepted

Sort by
0
Accepted
Dess | Tech Support Engineer, Principal
Telerik team
answered on 26 Jul 2018, 11:38 AM
Hello, Dominik,    

RadGridView is capable of fetching bindable properties and data. However, one important issue must be noted: during the data binding process, the grid extracts the data from the data source, but for any later changes in the data source, RadGridView should be notified. Your bindable collection and business objects should follow some standards established in .NET in order to notify RadGridView about the changes. Additional information is available in the following help article: https://docs.telerik.com/devtools/winforms/gridview/populating-with-data/reflecting-custom-object-changes-in-rgv

Refreshing the MasterTemplate is a suitable approach to force the proper information to be displayed. As to the scrollbar, you can store its value before the refresh and restore it after that as it is demonstrated below: 

int vScrollValue = this.radGridView1.TableElement.VScrollBar.Value;
this.radGridView1.MasterTemplate.Refresh();
this.radGridView1.TableElement.VScrollBar.Value = vScrollValue;

I hope this information helps. If you have any additional questions, please let me know.  
 
Regards,
Dess
Progress Telerik
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
konrad
Top achievements
Rank 1
answered on 30 Jul 2018, 10:33 AM
Thanks, that's all it needs.
0
konrad
Top achievements
Rank 1
answered on 27 Sep 2018, 07:57 AM

One more question, because i found MasterTemplate.Refresh(); really slow when I have 1-5k rows and i need to update only few of them.

So right now trying to use InvalidateRow() and the content of cell is updated properly, but how to update sorting and grouping?

For example: I have "City" column grouped. When I change the cell text in that column by InvalidateRow(), row stay in the same position. It should go to different group. Same with sorting.  

 

Is there any way to "InvalidateSorting()" or "InvalidateGrouping()"?

0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 28 Sep 2018, 12:16 PM
Hello, Dominik, 

Refreshing the MasterTemplate will refresh all rows in the grid. Invalidating only the specific row is a good approach. However, note that if the custom class implements the INotifyPropertyChanged interface, the row is expected to be automatically updated accordingly when the underlying DataBoundItem is modified. As a result it will be repositioned in the correct group. Please refer to the attached gif file. I have also attached my sample project for your reference.

In case you are still experiencing any further difficulties, feel free to modify it in a way to reproduce the experienced issue and get back to me with it so I can investigate the precise case. Thank you in advance. 

I hope this information helps.

Regards,
Dess
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
konrad
Top achievements
Rank 1
answered on 28 Sep 2018, 02:35 PM

Thanks Dess for the answer, but I am not using BindingList. I am using ObservableCollection. 

 

0
Hristo
Telerik team
answered on 01 Oct 2018, 08:51 AM
Hi Dominik,

In the discussed setup if you bind the grid to the System.Collections.ObjectModel.ObservableCollection<T>, this collection will not raise the CollectionChanged event when you update a property in the data-bound object. Not raising the CollectionChanged event will not notify the currency manager of the grid that the object has changed, hence the grid cell will not update. The cell in the grid will be updated after selecting the modified row as current and then changing it. This will trigger synchronization between the cell and the data bound object. A similar behavior can be observed with the Microsoft implementation of the DataGridView control as well. I can suggest using a BindingList which is standard for WinForms and it will raise its ListChanged event notifying any subscribers whenever an item was updated.

Let me know if you need further assistance.

Regards,
Hristo
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
konrad
Top achievements
Rank 1
answered on 02 Oct 2018, 09:46 AM

Thanks for clear explanation.

I am using ObservableCollection becouse it a little faster. I am also scared of memory licking and event bubbling. :) 

But still if I want to use ObservableCollection and InvalidateRow(), is there any way to force sorting and grouping refresh?

0
Hristo
Telerik team
answered on 02 Oct 2018, 01:11 PM
Hello Dominik,

If you will be using the observable collection, you will need to manually update the grid like this: 
private void radButton1_Click(object sender, EventArgs e)
{
    collectionOfStudents[1].Grade = "A-";;
    this.radGridView1.TableElement.Update(Telerik.WinControls.UI.GridUINotifyAction.DataChanged);
}



Regards,
Hristo
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
konrad
Top achievements
Rank 1
answered on 04 Oct 2018, 11:12 AM

Value in the cell changed but row stay in the same group :(

I also try using GridUINotifyAction.GroupingChanged with 0 result.

0
Hristo
Telerik team
answered on 04 Oct 2018, 11:57 AM
Hi Dominik,

You can also refresh the master template and this will force the groups to be rebuilt:
private void radButton1_Click(object sender, EventArgs e)
{
    collectionOfStudents[1].Grade = "A-";
    this.radGridView1.MasterTemplate.Refresh();
}

I am also attaching a short video showing the result on my end. Let me know if you have other questions.

Regards,
Hristo
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
konrad
Top achievements
Rank 1
answered on 04 Oct 2018, 12:37 PM

I have the impression that we are in a loop. :)

I don't want to use MasterTemplate.Refresh(). This work slow when I have  a lot of rows to update (as if he was refreshing the whole grid)

Here is my sample code. Just run new Test().Start();

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Forms;
using Telerik.WinControls.UI;
 
public class Test
{
    public void Start()
    {
 
        var grid = new RadGridView()
        {
            Dock = DockStyle.Fill,
            AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill,
            ShowGroupedColumns = true,
            ShowGroupPanel = true,
            AutoExpandGroups = true
        };
         
        var observableCollection = new ObservableCollection<Item>();
        observableCollection.Add(new Item() { Group = "Group 1 " });
        observableCollection.Add(new Item() { Group = "Group 1 " });
        observableCollection.Add(new Item() { Group = "Group 1 " });
        observableCollection.Add(new Item() { Group = "Group 2 " });
        observableCollection.Add(new Item() { Group = "Group 2 " });
        observableCollection.Add(new Item() { Group = "Group 3 " });
        observableCollection.Add(new Item() { Group = "Group 3 " });
 
        grid.DataSource = observableCollection;
 
        grid.GroupDescriptors.Add("Group", ListSortDirection.Ascending);
 
 
        var button = new RadButton() { Text = "Change", Dock = DockStyle.Top };
        button.Click += (x, y) =>
        {
            observableCollection[5].Group = "Group 0";
 
            grid.TableElement.Update(GridUINotifyAction.DataChanged);
 
            // code here to redraw grouping & sorting
             
        };
 
        var form = new RadForm();
        form.Height = 500;
        form.Controls.Add(grid);
        form.Controls.Add(button);
        form.ShowDialog();
    }
 
}
 
public class Item : System.ComponentModel.INotifyPropertyChanged
{
    private String _group;
 
    public String Group
    {
        get { return _group; }
        set
        {
            if (_group != value)
            {
                _group = value;
                OnPropertyChanged("Group");
            }
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

0
Hristo
Telerik team
answered on 04 Oct 2018, 01:58 PM
Hi Dominik,

As I said before, the observable collection is not raising the CollectionChanged event when you are updating a property in the data-bound item this way. There is no way for the grid to know that there has been a change in the data source so please consider using a BindingList.

Updating the table element will not work in a scenario in which you have grouped the grid by the same field as the one you are changing. Updating the table element will update the visual cell elements and in your scenario, there is no such cell because the control has been grouped by that cell/field. For example, you can test by grouping the grid according to a different column, and see that updating the table element will work. For the other case, it will be necessary to refresh the template as in my previous code snippet. To tell you honestly, I see no reason for not using a BindingList.

Let me know if you have other questions.

Regards,
Hristo
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Tags
GridView
Asked by
konrad
Top achievements
Rank 1
Answers by
Dess | Tech Support Engineer, Principal
Telerik team
konrad
Top achievements
Rank 1
Hristo
Telerik team
Share this question
or