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
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.
Dess
Progress Telerik
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()"?
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
Thanks Dess for the answer, but I am not using BindingList. I am using ObservableCollection.
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
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?
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
Value in the cell changed but row stay in the same group :(
I also try using GridUINotifyAction.GroupingChanged with 0 result.
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
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));
}
}
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