I have a datarepeater, with a datagridview in each row of the datarepeater.
When I add data to the first datagridview and the second, I get this -
Then, if I was to scroll down to a datarepeater row further down the page, then scroll to the top, we get this -
Note the items have changed position. If I was to add rows to many of the datagridviews, it gets very messy when I scroll.
Any ideas why this might be happening?
I have come across a similar problem with following setup:
I would filter (or not) my list and select items from repeater. But when I scrolled, my selected rows would not be tracked. Random rows were selected when I scrolled instead.
I think you may be experiencing the same issue. I have no proof about what I'm saying and I could not in that time find the answer on SO either, but I think it's related to how the repeater works.
It specifies your item(row) index based on displayed items (items which are visible at a certain time). This way it is possible for a fast scrollable component, while repeating controls.
Imagine how it would be if you had 10 controls per row and had 30.000 rows to display. What do you think that would happen if the repeater had to create 300.000 controls?
For this reason (and once more I am guessing, these are my assumptions as the documentations is very scarce - as you may know by now) the repeater creates only controls for items that fit your repeater area and recycles them.
This means that if you do some sort of operation on item on index XX and scroll, since the items are not in same index the repeater will flip out, since indexes are recalculated when you scroll.
Ok, now that I answered your question about what's going on, let's see how to fix it:
First, add a Label
to the ItemTemplate
of your repeater. This label will be used to bind your item Id
property (or something of the sort). Also, set your label Visible property to false to keep this hidden.
On my form I add these fields:
// I use an observable collection to be notified when it changes
private ObservableCollection<YourItem> _allItems =
new ObservableCollection<YourItem>();
private BindingSource _bindingSource;
Then bind your collection to the repeated (I do this in OnLoad)
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
...
_bindingSource = new BindingSource();
_bindingSource.DataSource = _allItems;
// my hidden label // All my items have an Id property
_labelHiddenId.DataBindings.Add("Text", BindingSource, "Id");
_dataRepeaterList.DataSource = _bindingSource;
_allItems.CollectionChanged += AllItems_CollectionChanged;
}
my listener:
protected override void AllItems_CollectionChanged(object sender,
NotifyCollectionChangedEventArgs e)
{
RefreshRepeater();
}
my refresh method:
protected void RefreshRepeater(bool search = false)
{
if (_dataRepeaterList.InvokeRequired)
{
_dataRepeaterList.Invoke((Action)(() => { RefreshRepeater(search); }));
return;
}
_bindingSource.DataSource = null; // Clear binding source first
_bindingSource.DataSource = _allItems.ToList();
_dataRepeaterList.DataSource = null; // Clear datasource first
_dataRepeaterList.DataSource = _bindingSource;
_dataRepeaterList.Refresh();
}
my draw item method, which is where I fill most of my row info:
protected override void DataRepeater_DrawItem(object sender,
DataRepeaterItemEventArgs e)
{
var dataSourceEntity = GetObjectFromDataSource(e.DataRepeaterItem);
var checkedComponent = _checkedItems.SingleOrDefault(
x => x.Equals(dataSourceEntity));
// Get current item control to fill. Something like
var grid = e.DataRepeaterItem.Controls["yourgridiew"] as DataGridView;
// Do stuff, you are messing with the right object :)
}
And my last piece:
protected override T GetObjectFromDataSource(DataRepeaterItem dataRepeaterItem)
{
if (dataRepeaterItem == null)
return null;
var hiddenIdLabel = (Label)dataRepeaterItem.Controls[_labelHiddenId.Name];
return _allItems.FirstOrDefault((entity) => entity.Id.ToString().Equals(hiddenIdLabel.Text));
}
This code has not seen a compiler, but it should set you on the right track.
To sum it up:
This took a long time to find and implement, but hopefully it will be easier for you :)