Сохранить изменения в связанном DataGridView с активным фильтром

У меня есть DataGridView, который заполняется BindingSource. Каждый раз, когда пользователь изменяет строку и переходит к другой строке (каждый раз, когда измененная строка теряет фокус), это вызывает событие RowValidated.
В этом случае элементы DataGridView.CurrentRow изменяются в SQLServer с помощью хранимой процедуры.

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

Я не могу использовать метод TableAdapter.Update(), потому что DataSet представляет собой объединение нескольких таблиц и не генерируется автоматически.

Есть ли какое-либо событие, которое запускается перед эффектами фильтра? Я бы принял в качестве ответа любой другой подход.

Редактировать: когда ячейка изменяется, сохраняется в списке значение идентификатора этой строки. Код в RowValidated инкапсулирован в
if (ListOfIds.Contains(DataGridView.CurrentRow.Cells["ID"])){StoredProcedure();}

Можете ли вы показать нам соответствующий код?

Hypenate 14.12.2020 11:06

Я вижу проблему общей. Какой код вы хотели бы видеть?

This_place_is_hard_on_newers 14.12.2020 11:08

Не используйте событие RowValidated для сохранения данных. Потому что он срабатывает даже тогда, когда вы перемещаете фокус по строкам.

Alexander Petrov 14.12.2020 11:55
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
616
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Редко бывает хорошей идеей читать и записывать значения ячеек самостоятельно. Использование DataBinding обычно является более простым методом.

Кажется, вы уже используете BindingSource, но по какой-то причине вы читаете измененную строку из отображаемых данных, а не из исходного BindingSource.

Я не уверен, что разумно обновлять базу данных, как только оператор переходит к новой строке. Что, если он не знает значения для заполнения и хочет прокрутить вниз, чтобы проверить другую строку? Рассмотрите возможность изменения интерфейса таким образом, чтобы оператор мог указать, что он закончил редактирование всех данных. Например кнопка. Но это немного не ваш вопрос.

Если вы поместите свои данные в BindingList и назначите эти данные источнику данных вашего DataGridView, то каждое изменение данных в DataGridView будет автоматически обновляться в BindingList. Используйте событие BindingList.ListChanged, чтобы получить уведомление, или используйте вышеупомянутую кнопку перед обработкой измененных данных.

BindingList<Customer> DisplayedCustomers {get; } = new BindingList<Customer>();

public MyForm()
{
    this.InitializeComponents();

    this.DataGridView1.DataSource = this.DisplayedCustomers();
    this.BindingListView.ListChanged += BindingListChanged;
}

Отображается пустой DataGridView. Чтобы заполнить его Клиентами:

private InitializeDataGridView()
{
    IEnumerable<Customer> customers = this.QueryCustomers();
    foreach (var customer in Customers)
        this.Customers.Add(customer);
}

Это автоматически покажет всех клиентов в вашем DataGridView. Увы, вы получите событие один раз для каждого клиента. Если вы этого не хотите, попробуйте создать новый BindingList и назначить его источнику данных DataGridView. Не забудьте отписаться от старого BindingList и подписаться на событие нового BindingList.

private void BindingListChanged(object sender, ListChangedEventArgs e)
{
     BindingList<Customer> bindingList = (BindingList<Customer>)sender;
     // use e.ListChangedType to detect what has changed:
     // item added / removed / moved to a new location / value changed?

     switch (e.ListChangedType)
     {
         case ListChangedType.ItemChanged:
             var changedCustomer = bindingList[e.NewIndex];
             ProcessChangedCustomer(changeCustomer);
             break;
         case ...
    }
}

Преимущество использования BindingList вместо того, чтобы возиться со значениями ячеек DataGridView, заключается в том, что вы отделяете данные от того, как эти данные передаются оператору. Это упрощает повторное использование (показывать его в ComboBox вместо DataGridView? Продолжайте, изменения минимальны), упрощает модульное тестирование: BindingList также работает, если нет формы; и, следовательно, легче поддерживать и изменять.

И последний совет: чтобы упростить фильтрацию по свойствам (показывать только тех клиентов, которые живут в Нью-Йорке) и упростить сортировку, рассмотрите возможность использования пакета nuget Equin.ApplicationFramework.BindingListView

List<Customer> customers = GetCustomers();
BindingListView<Customer> view = new BindingListView<Customer>(customers);
dataGridView1.DataSource = view;

И Бинго: бесплатная сортировка щелчком мыши по заголовку столбца. Он даже запоминает, следует ли сортировать по возрастанию или по убыванию, и показывает символ сортировки (стрелка, указывающая направление сортировки).

Фильтрация:

void FilerCustomersByCity(string city)
{
    view.ApplyFilter(delegate(Customer) customer => customer.City == city);
}

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

This_place_is_hard_on_newers 15.12.2020 09:29

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

Harald Coppoolse 15.12.2020 10:49

Другие вопросы по теме