Страницы

Поиск по вопросам

Показаны сообщения с ярлыком datatable. Показать все сообщения
Показаны сообщения с ярлыком datatable. Показать все сообщения

четверг, 5 марта 2020 г.

Как сделать чтобы AutoIncrement в dataGridView увеличивался только при добавлении строки

#c_sharp #winforms #datagridview #datatable


Код

   // *** создаю DataTable
dt_028 = new DataTable();

// *** Добавляю поля в DataTable
// поле Автоинкремент
workColumn = dt_028.Columns.Add("ID", typeof(Int32));
workColumn.AutoIncrement = true;
workColumn.AutoIncrementSeed = 1;
workColumn.AutoIncrementStep = 1;

// поля DataTable
dt_028.Columns.Add("pole_name_1", typeof(String));
dt_028.Columns.Add("pole_name_2", typeof(String));
dt_028.Columns.Add("pole_name_3", typeof(String));

// *** Отображаю DataTable в dataGridView
dataGridView1.DataSource = dt_028;


Когда перемещаю курсор в dataGridView с предпоследней строки на последнюю, увеличивается
значение AutoIncrement в поле "ID".
Т.е. переместил курсор на последнюю строку, но строку не добавил, а AutoIncrement
увеличился.

ВОПРОС
Как сделать чтобы автоинкремент увеличивался только при добавлении строки dataGridView,
а не просто при нахождении курсора на последней строке?

СКРИН


    


Ответы

Ответ 1



На самом деле, перемещение на последнюю строку в DataGridView а потом обратно, приводит к тому, что в DataTable, который указан в качестве источника данных, вставляется новая строка. Вставка новой строки приводит к инкременту поля ID, но т.к. строка на самом деле вставлена не была, происходит отклонение последних изменений - DataTable.RejectChanges(), т.е. тех изменений, которые произошли с момента последнего вызова DataTable.AcceptChanges(), при этом значение инкремента не сбрасывается, в связи с чем при новом перемещении на последную строку в DataGridView значение ID не то, которое вы ожидали увидеть. Что можно сделать? Решение № 1 Инкрементировать вручную, т.е. отключить workColumn.AutoIncrement на колонке ID и выставлять значение самостоятельно. private void FormLoad(object sender, EventArgs e) { _dt = new DataTable(); // Подписываемся на событие вставки новой строки. _dt.TableNewRow += DataTableNewRow; _dt.Columns.Add("ID", typeof(int)); _dt.Columns.Add("pole_name_1", typeof(string)); _dt.Columns.Add("pole_name_2", typeof(string)); _dt.Columns.Add("pole_name_3", typeof(string)); _dataGridView.DataSource = _dt; } private void DataTableNewRow(object sender, DataTableNewRowEventArgs dataTableNewRowEventArgs) { // Инкрементируем ID. dataTableNewRowEventArgs.Row["ID"] = _dt.Rows.Count + 1; } Решение № 2 Возложить задачу по генерации ID на вашу БД, что на мой взгляд более правильно. Решение № 3 Вместо типа int использовать тип Guid, при условии необходимости генерации ID на клиенте.

Ответ 2



Убрать автоинкремент у данного столбца. Остаётся лишь: workColumn = dt_028.Columns.Add("ID", typeof(Int32)); Подписать DataTable на событие добавления новой строки: dt_028.TableNewRow += Dt_028_TableNewRow; В обработчике события вставляем нужное значение: private void Dt_028_TableNewRow(object sender, DataTableNewRowEventArgs e) { e.Row["ID"] = dt_028.Rows.Count; } Ещё лучше вообще убрать эту колонку (вариант - сделать её скрытой). А номера строкам давать при сохранении данных в БД/файл. Собственно, а нужны ли вообще эти номера? В БД айдишник должен быть свой. А в файле он не нужен.

понедельник, 8 июля 2019 г.

Как сделать чтобы данные сохранённые при отладке в таблице отображались после сборки в *.exe файле?

Имеется две формы: главная, подчинённая.
Сценарий
Запускаю отладку; Создаю таблицу public DataTable dt_1 Заполняю таблицу через dataGridView1 Сохраняю таблицу в Settings.settings в переменную public global::System.Data.DataTable sett_frm_1_dt_1 Останавливаю отладку; Выполняю сборку проекта; Запускаю файл rsh.exe (c:...
sh\bin\Debug);
Проблема: После запуска rsh.exe переменная public global::System.Data.DataTable sett_frm_1_dt_1 пуста.
Код главной формы
public partial class Form1 : Form { public Form1() { InitializeComponent(); } // Form1()
// ФОРМЫ Form2 frm_2; // Form2 public DataTable dt_1;
private void button1_Click(object sender, EventArgs e) { // Form2 frm_2 = new Form2(); frm_2.Owner = this; frm_2.Show();/* или F2.ShowDialog();*/ } }
Код подчинённой формы
public partial class Form2 : Form { public Form2() { InitializeComponent(); } // public Form2()
Form1 frm_1;
private void Form2_Load(object sender, EventArgs e) { frm_1 = this.Owner as Form1; fnk_crt_dt_1(); }
private void Form2_Show(object sender, EventArgs e) { #region *** СОБЫТИЯ. f_prt_1.dt_030_html *** // Подписываемся на событие вставки новой строки.// frm_1.dt_1.TableNewRow += DataTableNewRow; // // СОБЫТИЕ. Происходит после успешного изменения DataRow frm_1.dt_1.RowChanged += new DataRowChangeEventHandler(Row_Changed); // // СОБЫТИЕ. Происходит после удаления строки в таблице. frm_1.dt_1.RowDeleted += new DataRowChangeEventHandler(Row_Deleted); // #endregion *** СОБЫТИЯ. f_prt_1.dt_030_html ***. КОНЕЦ ХХХ // извлечь таблицу из Settings // fnk_frm_1_dt_1_fr_set(); } // Form2_Show
// СОБЫТИЕ. ПРИСВОИТЬ ID // private void DataTableNewRow(object sender, DataTableNewRowEventArgs dataTableNewRowEventArgs) { try { int max = (int)frm_1.dt_1.Compute("Max(ID)", ""); dataTableNewRowEventArgs.Row["ID"] = max + 1; // dataTableNewRowEventArgs - вызывает событие TableNewRow. } catch { } }
// СОБЫТИЕ. Происходит после успешного изменения DataRow private void Row_Changed(object sender, DataRowChangeEventArgs e) // { Properties.Settings.Default.sett_frm_1_dt_1 = frm_1.dt_1; Properties.Settings.Default.Save(); }
// СОБЫТИЕ. Происходит после удаления строки в таблице. private void Row_Deleted(object sender, DataRowChangeEventArgs e) { Properties.Settings.Default.sett_frm_1_dt_1 = frm_1.dt_1; Properties.Settings.Default.Save(); }
// *** *** *** *** // ФУНКЦИИ // *** *** *** ***
// создаём таблицу public void fnk_crt_dt_1() { frm_1.dt_1 = new DataTable(); // BS_029_html = new BindingSource(); frm_1.dt_1.TableName = "frm_1_dt_1_Name";
// ДОБАВЛЕНИЕ ПОЛЕЙ frm_1.dt_1.Columns.Add("ID", typeof(Int32)); frm_1.dt_1.Columns.Add("pl_1", typeof(String)); // Имя html сценария frm_1.dt_1.Columns.Add("pl_2", typeof(String)); frm_1.dt_1.Columns.Add("pl_3", typeof(String));
// добавляем первый 'ID' = 1 DataRow newRow = frm_1.dt_1.NewRow(); newRow["ID"] = 1; frm_1.dt_1.Rows.Add(newRow);
dataGridView1.DataSource = frm_1.dt_1; }
public void fnk_frm_1_dt_1_in_set() // сохранить { Properties.Settings.Default.sett_frm_1_dt_1 = frm_1.dt_1; Properties.Settings.Default.Save(); }
public void fnk_frm_1_dt_1_fr_set() // извлечь { frm_1.dt_1 = Properties.Settings.Default.sett_frm_1_dt_1; dataGridView1.DataSource = frm_1.dt_1; }
// *** *** *** *** // КНОПКИ // *** *** *** ***
// создаём таблицу private void button1_Click(object sender, EventArgs e) { fnk_crt_dt_1(); }
// сохранить таблицу private void button2_Click(object sender, EventArgs e) { fnk_frm_1_dt_1_in_set(); }
// извлечь таблицу private void button3_Click(object sender, EventArgs e) { fnk_frm_1_dt_1_fr_set(); }
} // Form2 : Form
ВОПРОС
Как сделать чтобы данные сохранённые при отладке в переменнуюpublic global::System.Data.DataTable sett_frm_1_dt_1 после сборки отображались в rsh.exe файле? Также как сделать чтобы данные отображались, если файл rsh.exe перемещён в другую папку?
Скрин


Ответ

Насколько я понял, если два раза запустить программу из Visual Studio то таблица сохраняется и проблема состоит именно в том, что настройки не сохраняются при разном способе запуска (из среды и вручную).
Проблема
В папке Debug кроме rsh.exe есть еще файл rsh.vshost.exe. При откладке из Visual Studio запускается rsh.vshost.exe.
Пользовательские настройки сохраняются в расположении, которое зависит от имени файла. Поэтому для rsh.exe и rsh.vshost.exe будут разные настройки (что логично для двух разных приложений).
Сохранение настроек
Путь, в котором сохраняются пользовательские настройки, для автономного приложения выглядит примерно так:
%LOCALAPPDATA%\(PUBLISHER)\(APP_NAME).exe_(StrongName|Url)_(HASH)\(APP_VERSION)\
, по порядку:
PUBLISHER — организация разработчка, прописывается в настройках проекта; APP_NAME — имя сборки (в данном случае исполняемого файла); HASH — хэш строгого имени либо, если его нет, пути; APP_VERSION — версия, так же прописывается в настройках проекта.
В Вашем случае проблема в том, что при отсутствии строгого имени у сборки хэш рассчитывается по пути к файлу, которое в данном случае будет отличаться.
Подробнее про сохранение пользовательских настроек можно почитать здесь:
Client Settings FAQ — MSDN Blogs. When using a Settings.settings file in .NET, where is the config actually stored?
Решение:
Как вариант, можно подписать приложение и установить строгое имя. Это можно сделать в Visual Studio (смотрите руководство). В этом случае настройки приложения не будут зависеть от расположения файла и rsh.exe будет загружать сохраненные настройки после перемещения в другую папку.
UPDATE: Как выяснилось, APP_NAME это все-таки имя файла, а не имя сборки, соответственно, для rsh.vshost.exe настройки будут все-таки разными.
Если очень нужно (интересно, зачем?) чтобы во время отладки использовались те же настройки, то можно отключить создание отдельного исполняемого файла rsh.vshost.exe.
В настройках проекта во вкладке «Debug» (скорее всего «Отладка», нет русифицированной среды под рукой) снимите флажок «Enable Visual Studio hosting process» («Разрешить главный процесс Visual Studio»). После этого Visual Studio и во время отладки будет запускать rsh.exe напрямую.
Отключение приведет к тому, что отдельные функции во время отладки не будут доступны (подробнее в руководстве на MSDN). Это не должно быть проблемой, можно устанавливать флажок для разработки/отладки и снимать его когда нужна синхронизация настроек.
P.S. Не мог воспроизвести проблему с vshost.exe т.к. APP_NAME при сохранении настроек обрезается до первых 26 символов. Т.о. если дать приложению длинное название, например, rsh_WithExtremelyLongName, то путь к настройкам для .exe и .vshost.exe совпадет.