У меня есть DataGridView, который заполняется BindingSource. Каждый раз, когда пользователь изменяет строку и переходит к другой строке (каждый раз, когда измененная строка теряет фокус), это вызывает событие RowValidated
.
В этом случае элементы DataGridView.CurrentRow
изменяются в SQLServer с помощью хранимой процедуры.
Когда BindingSource имеет активный фильтр, этот подход не работает. Потому что, если изменяется ячейка фильтруемого столбца, строка исчезает (из-за фильтра), и мой метод улавливает DataGridView.CurrentRow
как следующий.
Я не могу использовать метод TableAdapter.Update()
, потому что DataSet представляет собой объединение нескольких таблиц и не генерируется автоматически.
Есть ли какое-либо событие, которое запускается перед эффектами фильтра? Я бы принял в качестве ответа любой другой подход.
Редактировать: когда ячейка изменяется, сохраняется в списке значение идентификатора этой строки. Код в RowValidated
инкапсулирован в if (ListOfIds.Contains(DataGridView.CurrentRow.Cells["ID"])){StoredProcedure();}
Я вижу проблему общей. Какой код вы хотели бы видеть?
Не используйте событие RowValidated
для сохранения данных. Потому что он срабатывает даже тогда, когда вы перемещаете фокус по строкам.
Редко бывает хорошей идеей читать и записывать значения ячеек самостоятельно. Использование 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);
}
Бесконечное спасибо за развернутый ответ. Я нахожусь на стажировке, и это очень помогло мне иметь четкую перспективу.
При разработке программного обеспечения всегда старайтесь отделить данные от того, как они отображаются. Это упрощает модульное тестирование данных без пользовательского интерфейса. Если вы хотите изменить способ отображения данных, вам не придется менять внутреннюю модель, ни то, как она заполняется, ни то, как она сохраняется. Разделение модели и представления также приводит к тому, что изменения в вашей внутренней модели не означают больших изменений в вашем отображении. Подумайте о том, чтобы прочитать справочную информацию о модели - представление - модель представления
Можете ли вы показать нам соответствующий код?