Datarepeater со встроенными изменяющимися таблицами datagridview

У меня есть повторитель данных с представлением данных в каждой строке повторителя данных.

Когда я добавляю данные в первый datagridview и второй, я получаю это -

Перед прокруткой

Затем, если бы я прокрутил вниз до строки ретранслятора данных дальше по странице, а затем прокрутил вверх, мы получили это -

После прокрутки

Обратите внимание, что элементы изменили свое положение. Если бы мне нужно было добавить строки во многие представления сетки данных, при прокрутке все стало бы очень грязно.

Любые идеи, почему это может происходить?


person dynamicuser    schedule 03.09.2013    source источник


Ответы (1)


Я столкнулся с аналогичной проблемой со следующей настройкой:

  • Флажок на строку
  • Текстовое поле поиска (перед управлением повторителем, для фильтрации элементов)
  • Много элементов в повторителе (по крайней мере, число достаточно большое, чтобы его можно было прокручивать)

Я бы фильтровал (или нет) свой список и выбирал элементы из повторителя. Но когда я прокручивал, мои выбранные строки не отслеживались. Вместо этого при прокрутке были выбраны случайные строки.

Я думаю, что вы можете столкнуться с той же проблемой. У меня нет доказательств того, что я говорю, и я не мог в то время найти ответ на SO, но я думаю, что это связано с тем, как работает повторитель.

Он указывает индекс вашего элемента (строки) на основе отображаемых элементов (элементов, которые видны в определенное время). Таким образом, можно быстро прокручивать компонент, повторяя элементы управления.

Представьте, что было бы, если бы у вас было 10 элементов управления в строке и отображалось бы 30 000 строк. Как вы думаете, что произойдет, если повторителю придется создать 300 000 элементов управления?

По этой причине (и еще раз я предполагаю, что это мои предположения, поскольку документации очень мало - как вы, возможно, уже знаете) повторитель создает только элементы управления для элементов, которые соответствуют вашей области повторителя, и перерабатывает их.

Это означает, что если вы выполняете какую-то операцию над элементом по индексу XX и прокручиваете, поскольку элементы не находятся в одном индексе, повторитель будет переворачиваться, поскольку индексы пересчитываются при прокрутке.

Хорошо, теперь, когда я ответил на ваш вопрос о том, что происходит, давайте посмотрим, как это исправить:

Сначала добавьте Label к ItemTemplate ретранслятора. Эта метка будет использоваться для привязки свойства вашего элемента Id (или чего-то в этом роде). Кроме того, установите для свойства label Visible значение false, чтобы скрыть это.

В моей форме я добавляю эти поля:

// I use an observable collection to be notified when it changes
private ObservableCollection<YourItem> _allItems = 
    new ObservableCollection<YourItem>(); 
private BindingSource _bindingSource;

Затем привяжите свою коллекцию к повтору (я делаю это в 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;
}

мой слушатель:

protected override void AllItems_CollectionChanged(object sender, 
    NotifyCollectionChangedEventArgs e)
{
    RefreshRepeater();
}

мой метод обновления:

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();
 }

мой метод рисования элемента, в котором я заполняю большую часть информации о строке:

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 :)
}

И моя последняя часть:

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));
}

Этот код не видел компилятора, но он должен направить вас на правильный путь.

Подвести итог:

  • Создайте скрытую метку в шаблоне элемента
  • Создайте наблюдаемую коллекцию и при изменении события обновите повторитель
  • Создайте источник привязки, установите его источник данных в свою коллекцию.
  • Сделайте так, чтобы ваши элементы имели общий идентификатор и привязали этот идентификатор к повторителю.
  • При обновлении ретранслятора новыми данными сбросьте источник данных (на всякий случай)
  • Создайте метод для поиска исходного объекта (объекта источника данных) на основе текущей строки повторителя.
  • Получите контроль над текущим объектом (объектом источника данных) и примените к нему операции.

Это заняло много времени, чтобы найти и реализовать, но, надеюсь, вам будет легче :)

person Joel    schedule 11.09.2013