Winforms Databound Combobox обновляет данные, но не изменяет состояние строки

#c# #winforms #data-binding #combobox

#c# #winforms #привязка данных #выпадающий список

Вопрос:

.NET 4.7.2 Winforms c#

Есть форма с кучей выпадающих списков. Выпадающий список для всех. Выпадающие списки заполняются либо из таблиц данных, либо из словарей. Они привязаны к столбцам в таблице данных для набора данных.

Выпадающие списки заполняются и привязываются к данным следующим образом:

         dSDO = new Dictionary<bool, string>
        {
            {true,"Yes" },
            {false,"No" }
        };
        CB1.DataSource = new BindingSource(dSDO, null);;
        CB1.DisplayMember = "Value";
        CB1.ValueMember = "Key";
        CB2.DataSource = _dtCommodity;
        CB2.DisplayMember = "CommodityAbbr";
        CB2.ValueMember = "CommodityID";
        // Databindings tried both before and after 
        CB1.DataBindings.Add("SelectedValue", dataset, "Tablename.colname1", true, DataSourceUpdateMode.OnPropertyChanged);
        CB1.DataBindings.Add("SelectedValue", dataset, 'Tablename.colname2", true, DataSourceUpdateMode.OnPropertyChanged);
  

Выбор другого элемента в выпадающем списке обновляет столбец в строке данных. Однако состояние строки остается неизменным, и обновление для строки не происходит. Явный вызов ValidateChildren для формы ничего не делает.

Этот код использовался для работы в более старых платформах .NET (4.0 и старше); кажется, что что-то изменилось, чтобы прервать обработку, или я что-то упустил, и Microsoft больше не так снисходительна.

Есть идеи?
Спасибо!

Комментарии:

1. Вызывали ли вы dataset.AcceptChanges(); после загрузки данных (чтобы установить статус для всех строк Unchanged )? Кроме того, я бы использовал BindingSource для обработки набора данных (установите DataSet в качестве источника данных) и используйте BindingSource для привязки ComboBox (установите DataSource член привязки к BindingSource). Привязка к вложенному объекту будет работать таким образом. Статус строки будет Modified , когда вы зафиксируете значение через выпадающий список. Источником данных ComboBox должен быть объект, который реализует INotifyPropertyChanged (там нет ListChanged событий).

2. Я не вызываю AcceptChanges — это установило бы статус без изменений. Я немедленно попробую это предложение.

3. При первой загрузке данных вы должны установить статус на Unchanged , в противном случае он останется Added , что неверно. У DataAdapter есть свойство, [DataAdapter].AcceptChangesDuringFill , которое используется именно для этого.

4. Моя проблема в том, что после изменения данных все еще отображается без изменений. Я меняю выделение в выпадающем списке, новое выбранное значение в выпадающем списке записывается в DataRow, но состояние строки остается неизменным. Изменение привязки данных полей к источнику привязки над набором данных не принесло никакой пользы. Тот же результат.

5. Затем добавьте BindingSource в качестве поля (например, internal BindingSource bsDataSet = null; ) bsDataSet = new BindingSource(dataset, null); CB1.DataBindings.Add("SelectedValue", bsDataSet, "Tablename.colname1", true, DataSourceUpdateMode.OnPropertyChanged); . Конечно, вы добавляете только один DataBinding , если вы попытаетесь добавить второй, вы получите исключение. Кстати, всегда устанавливайте DisplayMember и ValueMember (в этом порядке) перед DataSource .

Ответ №1:

Я нашел решение.

В соответствии с предложением от @Jimi я изменил код…

         bsDataSource = new BindingSource(dataSet, "[SqlTableName]");
        CB1.DataBindings.Add("SelectedValue", bsDataSource, "colname1", true, DataSourceUpdateMode.OnPropertyChanged);
        CB2.DataBindings.Add("SelectedValue", bsDataSource, "colname2", true, DataSourceUpdateMode.OnPropertyChanged);
  

А затем при сохранении я сделал это:

                 using (SqlDataAdapter da = new SqlDataAdapter(SqlCommandObject))
                {
                    using (SqlCommandBuilder cb = new SqlCommandBuilder(da))
                    {
                        da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
                        cb.ConflictOption = ConflictOption.OverwriteChanges;
                        cb.SetAllValues = false;
                       
                        da.InsertCommand = cb.GetInsertCommand(true);
                        da.UpdateCommand = cb.GetUpdateCommand(true);
                        da.DeleteCommand = cb.GetDeleteCommand(true);
                        try
                        {
                            // I Added this line
                            ((DataRowView)bsDataSource.Current).EndEdit();
                            // End of what I added
                            da.MissingMappingAction = MissingMappingAction.Passthrough;
                            iRowCount = da.Update(ds, ds.Tables[0].TableName);
                        }
                        catch (Exception ex)
                        {
                            // [error handling]
                        }
                    }
                }
  

Это привело к изменению состояния строки на измененное и успешному обновлению набора данных.

Итак, решение:

  1. Создайте BindingSource поверх объекта DataSet с именем таблицы соответствующей таблицы данных в качестве параметра 2
  2. Привязка каждого элемента управления к соответствующему имени столбца и указание источника привязки.
  3. Выполните EndEdit() над DataRowView, который находится в текущем свойстве.
  4. Затем выполните обновление DataAdapter.

Спасибо — Надеюсь, что это поможет кому-то еще.