Создание редактируемого списка сетки, привязанного к списку БД в VB.NET - PullRequest
0 голосов
/ 31 января 2020

У меня есть форма с 7 полями со списком, в которой при выборе значений и при нажатии кнопки сохранения данные сохраняются в основной БД, а затем отображаются в виде сетки под полями

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

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

Private Sub DataGridView1_RowHeaderMouseClick(sender As Object, e As 
DataGridViewCellMouseEventArgs) Handles DataGridView1.RowHeaderMouseClick
        MsgBox("Row Clicked")
        If e.RowIndex >= 0 Then
            Dim row As DataGridViewRow = DataGridView1.Rows(e.RowIndex)
            MsgBox(row.Cells(0).Value.ToString)
            MsgBox(row.Cells(1).Value.ToString)
            MsgBox(row.Cells(2).Value.ToString)
            MsgBox(row.Cells(3).Value.ToString)
            MsgBox(row.Cells(4).Value.ToString)
            MsgBox(row.Cells(5).Value.ToString)
            MsgBox(row.Cells(6).Value.ToString)
            DateTimePicker1.Value = row.Cells(0).Value


            ComboBox1.DataSource = Nothing
            ComboBox2.DataSource = Nothing
            ComboBox3.DataSource = Nothing
            ComboBox4.DataSource = Nothing
            ComboBox5.DataSource = Nothing
            ComboBox6.DataSource = Nothing
            ComboBox7.DataSource = Nothing
            ComboBox1.Items.Add(row.Cells(1).Value)
            ComboBox2.Items.Add(row.Cells(2).Value)
            ComboBox3.Items.Add(row.Cells(3).Value)
            ComboBox4.Items.Add(row.Cells(4).Value)
            ComboBox5.Items.Add(row.Cells(5).Value)
            ComboBox6.Items.Add(row.Cells(6).Value)
            ComboBox7.Items.Add(row.Cells(7).Value)
        End If

    End Sub

Примите во внимание любые мысли о том, как go двигаться вперед с этим.

Спасибо

Андрей

Редактировать: Форма изображения здесь

Код для значений поля со списком, вставленных в базу данных.

Private Sub LoadDataToQuery()
    Dim myTable As New DataTable()
    'Dim MyConn As New SqlConnection()
    Dim MyCmd As New SqlCommand()
    'Dim InputDate As DateTime

    'Parameters for insert query
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@InputDate", .SqlDbType = SqlDbType.DateTime, .Value = DateTimePicker1.Value})
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@staffMember", .SqlDbType = SqlDbType.NVarChar, .Value = ComboBox1.GetItemText(ComboBox1.SelectedItem)})
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@Ward", .SqlDbType = SqlDbType.NVarChar, .Value = ComboBox2.GetItemText(ComboBox2.SelectedItem)})
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@Defecit", .SqlDbType = SqlDbType.NVarChar, .Value = ComboBox3.GetItemText(ComboBox3.SelectedItem)})
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@Reason", .SqlDbType = SqlDbType.NVarChar, .Value = ComboBox4.GetItemText(ComboBox4.SelectedItem)})
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@Band", .SqlDbType = SqlDbType.Int, .Value = ComboBox5.GetItemText(ComboBox5.SelectedItem)})
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@AuthoriserName5", .SqlDbType = SqlDbType.NVarChar, .Value = ComboBox6.GetItemText(ComboBox6.SelectedItem)})
    MyCmd.Parameters.Add(New SqlParameter With {.ParameterName = "@AuthoriserName6", .SqlDbType = SqlDbType.NVarChar, .Value = ComboBox7.GetItemText(ComboBox7.SelectedItem)})


    'Open conection and run query
    myConn.Open()
    MyCmd.Connection = myConn
    'Create insert statement
    MyCmd.CommandText = "INSERT INTO OvertimeAuthorisationMain VALUES(@InputDate, @staffMember, @Ward, @Defecit, @Reason, @Band, @AuthoriserName5, @AuthoriserName6)"
    MyCmd.ExecuteNonQuery()

    MyCmd.Dispose()

End Sub

1 Ответ

0 голосов
/ 22 февраля 2020

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

Есть множество ComboBoxes выше DataGridView. Каждый из столбцов сетки соответствует определенному ComboBox. Если пользователь нажимает на строку в сетке, соответствующие поля со списком должны быть установлены на те же значения, которые находятся в «выбранной» строке в сетке. Кроме того, после того, как пользователь «выберет» строку в сетке и поля со списком заполнятся данными о «этих» строках, ТО ... затем пользователь может «изменить» некоторые значения в полях со списком, а затем нажать кнопку «Сохранить» сохранить выбранные значения поля со списком в «выбранную» строку в сетке. Кроме того, эти изменения также должны быть обновлены в базе данных. Я надеюсь, что у меня есть это право.

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

Ниже приведен рисунок формы код ниже управляет. Есть форма с сохранением Button, пятью (5) ComboBoxes и DataGridView. Используется таблица базы данных (TestCombos), которая имеет следующую схему…

RecordNumber    int PrimaryKey – not null
Member  nvarchar(50) - null
Ward    nvarchar(50) - null
Deficit int - null
Reason  nvarchar(50) - null
Band    nvarchar(50) - null

enter image description here

Из вашего опубликованного кода я не вижу « где »код« Обновление »базы данных с изменениями выбранной строки. Метод LoadDataToQuery кажется (неловко) «вставить» «новую» строку из поля со списком. Бьюсь об заклад, причина, по которой код «обновления» отсутствует, заключается в том, что из того, что я вижу в коде… Как бы вы ЗНАЛИ «какую» строку в таблице базы данных «обновить»? Другими словами, если пользователь «выбрал» строку, изменил поля со списком, а затем нажал кнопку «Сохранить». Мы бы знали, какая «строка» изменилась, поскольку она является выбранной строкой в ​​сетке, и из нее мы могли бы получить, какую строку выбрать в сетках DataSource DataTable… однако мы не обязательно ЗНАЛИ, какая строка в таблица базы данных для обновления.

Я не вижу ничего «уникального», которое бы идентифицировало одну строку из другой. Я вижу, как используется «Дата», но я также могу представить множество строк с одной и той же датой. Указывайте, что вам нужен какой-то уникальный идентификатор, чтобы указать на соответствующую строку в таблице базы данных. Вот почему я добавил столбец «RecordNumber» в таблицу и сделал его первичным ключом без нулей и, очевидно, без дубликатов. Таким образом, когда коду необходимо «обновить» запись в таблице базы данных, мы будем точно знать, какая именно.

Нет необходимости показывать этот столбец пользователю, однако вам потребуется убедитесь, что при добавлении «Новой» записи / строки, RecordNumber уникален. В этом примере код просто использует номер строки в таблице в качестве номера записи, если пользователь «добавляет» строку, RecordNumber для этой строки будет количеством строк в таблице + 1. Это будет работать для этот пример; Однако я НЕ рекомендую использовать эту стратегию. Если вы «удалите» строки, это вызовет проблемы. Поэтому я рекомендую другой подход для получения уникального ключа для новых строк.

Наличие каждой строки с уникальным ключом значительно упростит «обновление» значений в таблице базы данных и станет менее подверженным ошибкам при использовании предложения WHERE. в запросе, чтобы определить правильную строку для обновления.

Еще одна вещь, отсутствующая в вашем посте, это «какие» значения вы добавляете в поля со списком? Странное событие RowHeaderMouseClick появляется, чтобы ... захватить выбранный row, а затем вывести некоторые сообщения из ячеек выбранной строки. Тогда по неизвестным причинам ВСЕ поля со списком очищаются от предметов? ПОЧЕМУ? … Затем ячейки выбранной строки «добавляются» в соответствующие элементы комбинированного списка? … По сути, каждый раз, когда пользователь щелкает заголовок строки, любое значение в поле со списком удаляется, а значения ячеек выбранных строк в сетке добавляются в поля со списком. Это будет означать, что поля со списком будут иметь только ОДНО значение (1), и пользователь никогда не увидит поле со списком со «множественными» значениями.

Неизвестно, хотите ли вы, чтобы пользователь мог «добавлять» элементы в поля со списком, и «обычно» поля со списком имеют ИСПРАВЛЕННЫЕ значения, которые не изменяются; Тем не менее, я видел ситуации, когда элементы должны быть добавлены в поле со списком. К сожалению, этот пример НЕ позволяет пользователю «добавлять» новые элементы.

Учитывая это, я предполагаю, что вы хотите, чтобы комбинированные блоки содержали… «ВСЕ уникальные значения для соответствующего столбца в сетке» , Например, в поле со списком «Сотрудник» вы должны указать ВСЕ «разные» значения Сотрудника в таблице без дубликатов. Если вам известен заранее определенный набор значений, которые вы хотите использовать, вы можете сначала добавить эти значения. Однако возможно, что в данных МОЖЕТ быть значение, которое НЕ является одним из предопределенных значений. Эти значения НЕ будут отображаться в поле со списком, если вы не добавите их.

Поэтому, чтобы «почти» гарантировать, что ВСЕ значения находятся в поле со списком, сначала необходимо добавить предварительно определенные значения, а затем проверить данные для любых значений, которые НЕ являются частью предварительно определенных значений. Если вы найдете его, добавьте его в поле со списком, так же как и в данных. В этом примере НЕТ предопределенных значений для полей со списком. Код просто перебирает данные и извлекает уникальные / уникальные значения из каждого столбца.

Вы можете запросить базу данных для этих данных, однако нижеприведенный метод GetUniqueDataFromSource(colIndex As Int32, dt As DataTable, type As Int32) - это простой метод, который принимает столбец индекс для определения того, какой столбец данных мы хотим получить, DataTable, который содержит данные, и значение int для определения «типа» списка, который мы хотим вернуть, либо строковый, либо int.

Сначала «Тип» проверяется и создается новый список. Ноль (0) и пустая строка добавляются в поля со списком, чтобы облегчить добавление новых строк. Простое l oop через строки таблицы данных, чтобы добавить каждый элемент в список. Если список уже «содержит» это значение, оно НЕ добавляется в список (Дублировать). Наконец список сортируется и затем возвращается. Этот метод будет использоваться для установки каждого поля со списком DataSource на соответствующие значения для соответствующего столбца в сетке и будет называться ONCE для каждого поля со списком при загрузке формы.

Private Function GetUniqueDataFromSource(colIndex As Int32, dt As DataTable, type As Int32)
  Dim dataList
  If (type = 2) Then
    dataList = New List(Of Int32)
    dataList.Add(0)
  Else
    dataList = New List(Of String)
    dataList.Add("")
  End If
  Dim curItem
  For Each row As DataRow In dt.Rows
    curItem = row.ItemArray(colIndex)
    If (Not dataList.Contains(curItem)) Then
      dataList.Add(curItem)
    End If
  Next
  dataList.Sort()
  Return dataList
End Function

Это должно « заполните »поля со списком правильными данными. Однако, если пользователь выбирает строку, поля со списком не будут отражать значения из «выбранной» строки. Чтобы помочь, метод с именем UpdateCombosFromGrid() может быть полезным. Этот метод не принимает аргументов и просто устанавливает значение каждого поля со списком равным значению из текущей «выбранной» строки. Код проверяет, есть ли выбранная строка, а затем устанавливает соответствующее поле со списком с соответствующим значением и типом из сетки. Имейте в виду, что сетка SelectionMode ДОЛЖНА быть установлена ​​на «полный ряд». В противном случае DataGridView1.SelectedRows.Count всегда будет возвращать ноль (0).

Private Sub UpdateCombosFromGrid()
  If (DataGridView1.SelectedRows.Count > 0) Then
    Dim selectedRow = DataGridView1.SelectedRows(0)
    Dim value = 0
    ComboBox1.SelectedItem = selectedRow.Cells("Member").Value
    ComboBox2.SelectedItem = selectedRow.Cells("Ward").Value
    Integer.TryParse(selectedRow.Cells("Deficit").Value.ToString(), value)
    ComboBox3.SelectedItem = value
    ComboBox4.SelectedItem = selectedRow.Cells("Reason").Value
    ComboBox5.SelectedItem = selectedRow.Cells("Band").Value
  End If
End Sub

Мы можем использовать вышеописанный метод для установки значений поля со списком, когда форма загружается, а также когда пользователь меняет выбор сетки. Если пользователь выбирает другую строку, то поля со списком будут отражать это изменение. Однако, если пользователь выбирает строку «Новая», последнюю «пустую» строку в сетке, как показано на рисунке, то мы хотим «очистить» поля со списком. Это не действительно необходимо; однако, это было бы хорошим сигналом для пользователя, что они МОГУТ ДОБАВЛЯТЬ новые строки. Если выбранная строка НЕ ​​является новой строкой, вызовите вышеуказанный метод.

Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) Handles DataGridView1.SelectionChanged
  If (DataGridView1.SelectedRows.Count > 0) Then
    Dim selectedRow = DataGridView1.SelectedRows(0)
    If (selectedRow.IsNewRow) Then
      ComboBox1.SelectedItem = ""
      ComboBox2.SelectedItem = ""
      ComboBox3.SelectedItem = 0
      ComboBox4.SelectedItem = ""
      ComboBox5.SelectedItem = ""
    Else
      UpdateCombosFromGrid()
    End If
  End If
End Sub

Это должно обеспечить обновление полей со списком, чтобы они отражали «выбранную» строку сетки, когда пользователь выбирает другие строки.

Далее следует кнопка «Сохранить», и она действительно должна сделать две вещи: сначала нам нужно «обновить» «выбранную» строку в сетке И также «обновить» эту строку в базе данных. Чтобы помочь, метод, который делает обратный метод UpdateCombosFromGrid(). Как следует из названия, метод UpdateSelectedRowFromCombos() получает значения из полей со списком и устанавливает эти значения в «выбранную» строку в сетке.

Private Sub UpdateSelectedRowFromCombos()
  If (DataGridView1.SelectedRows.Count > 0) Then
    Dim selectedRow = DataGridView1.SelectedRows(0)
    Dim value = 0
    selectedRow.Cells("Member").Value = ComboBox1.SelectedValue
    selectedRow.Cells("Ward").Value = ComboBox2.SelectedValue
    Integer.TryParse(ComboBox3.SelectedValue, value)
    selectedRow.Cells("Deficit").Value = value
    selectedRow.Cells("Reason").Value = ComboBox4.SelectedValue
    selectedRow.Cells("Band").Value = ComboBox5.SelectedValue
  End If
End Sub

Это позаботится о получении новых значений в сетке, будь то обновление существующей строки или добавление новой строки. Однако «обновление» строки в таблице базы данных и «добавление» строки - это два разных запроса. Я уверен, что вы могли бы сделать один метод для этого, однако я сделаю два разных метода. Оба метода берут DataRow и либо «обновляют» существующую строку, либо «вставляют» новую строку.

Private Sub UpdateDB_WithRow(rowToUpdate As DataRow)
  Dim connString = "Server = localhost; Database = TestDB; Trusted_Connection = True;"
  Using conn As SqlConnection = New SqlConnection(connString)
    Dim cmd = New StringBuilder("UPDATE TestCombos SET Member = @Member, Ward = @Ward, ") 
    cmd.Append("Deficit = @Deficit, Reason = @Reason, Band = @Band ")
    cmd.Append("WHERE RecordNumber = @RecordNumber")
    conn.Open()
    Using da As SqlDataAdapter = New SqlDataAdapter()
      da.UpdateCommand = conn.CreateCommand()
      da.UpdateCommand.Parameters.AddWithValue("@Member", rowToUpdate("Member"))
      da.UpdateCommand.Parameters.AddWithValue("@Ward", rowToUpdate("Ward"))
      da.UpdateCommand.Parameters.AddWithValue("@Deficit", rowToUpdate("Deficit"))
      da.UpdateCommand.Parameters.AddWithValue("@Reason", rowToUpdate("Reason"))
      da.UpdateCommand.Parameters.AddWithValue("@Band", rowToUpdate("Band"))
      da.UpdateCommand.Parameters.AddWithValue("@RecordNumber", rowToUpdate("RecordNumber"))
      da.UpdateCommand.CommandText = cmd.ToString()
      da.UpdateCommand.ExecuteNonQuery()
    End Using
  End Using
End Sub

Вставляют новую строку…

Private Sub InsertNewRowToDB(rowToUpdate As DataRow)
  Dim connString = "Server = localhost; Database = TestDB; Trusted_Connection = True;"
  Using conn As SqlConnection = New SqlConnection(connString)
    Dim cmd = New StringBuilder("INSERT INTO TestCombos Values (@RecordNumber, @Member, @Ward, @Deficit, @Reason, @Band)")
    conn.Open()
    Using da As SqlDataAdapter = New SqlDataAdapter()
      da.InsertCommand = conn.CreateCommand()
      da.InsertCommand.Parameters.AddWithValue("@Member", rowToUpdate("Member"))
      da.InsertCommand.Parameters.AddWithValue("@Ward", rowToUpdate("Ward"))
      da.InsertCommand.Parameters.AddWithValue("@Deficit", rowToUpdate("Deficit"))
      da.InsertCommand.Parameters.AddWithValue("@Reason", rowToUpdate("Reason"))
      da.InsertCommand.Parameters.AddWithValue("@Band", rowToUpdate("Band"))
      da.InsertCommand.Parameters.AddWithValue("@RecordNumber", rowToUpdate("RecordNumber"))
      da.InsertCommand.CommandText = cmd.ToString()
      da.InsertCommand.ExecuteNonQuery()
    End Using
  End Using
End Sub

С помощью метода для обновления Выбранная строка и метод для обновления / добавления строки в базу данных, событие сохранения может выглядеть примерно так: *

Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
  Dim selectedRow = DataGridView1.SelectedRows(0)
  Dim newRow
  If (selectedRow.IsNewRow) Then
    newRow = ds.Tables("TestCombos").Rows.Add()
    newRow("RecordNumber") = ds.Tables("TestCombos").Rows.Count
    newRow("Member") = ComboBox1.SelectedItem
    newRow("Ward") = ComboBox2.SelectedItem
    newRow("Deficit") = ComboBox3.SelectedItem
    newRow("Reason") = ComboBox4.SelectedItem
    newRow("Band") = ComboBox5.SelectedItem
    DataGridView1.CurrentCell = DataGridView1.Rows(selectedRow.Index - 1).Cells(0)
    InsertNewRowToDB(newRow)
  Else
    UpdateSelectedRowFromCombos()
    Dim tableRowIndex = ds.Tables("TestCombos").Rows.IndexOf(DirectCast(selectedRow.DataBoundItem, DataRowView).Row)
    UpdateDB_WithRow(ds.Tables("TestCombos").Rows(tableRowIndex))
  End If
End Sub

Метод для получения данных из базы данных ...

Private Sub GetDataFromDB()
  ds = New DataSet()
  Dim connString = "Server = localhost; Database = TestDB; Trusted_Connection = True;"
  Dim query = "select * from TestCombos"
  Using conn = New SqlConnection(connString)
    Dim cmd = New SqlCommand(query, conn)
    conn.Open()
    Dim da = New SqlDataAdapter(cmd)
    da.Fill(ds, "TestCombos")
    conn.Close()
  End Using
End Sub

Далее нам нужен метод для установки значений каждого поля со списком после загрузки данных. Мы можем использовать метод GetUniqueDataFromSource, описанный ранее, и он может выглядеть следующим образом…

Private Sub SetComboBoxValues()
  ComboBox1.DataSource = GetUniqueDataFromSource(1, ds.Tables("TestCombos"), 1)
  ComboBox2.DataSource = GetUniqueDataFromSource(2, ds.Tables("TestCombos"), 1)
  ComboBox3.DataSource = GetUniqueDataFromSource(3, ds.Tables("TestCombos"), 2)
  ComboBox4.DataSource = GetUniqueDataFromSource(4, ds.Tables("TestCombos"), 1)
  ComboBox5.DataSource = GetUniqueDataFromSource(5, ds.Tables("TestCombos"), 1)
End Sub

Наконец, собрав все это вместе в событии загрузки формы…

Dim ds As DataSet

Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  GetDataFromDB()
  DataGridView1.DataSource = ds.Tables("TestCombos")
  SetComboBoxValues()
  UpdateCombosFromGrid()
  DataGridView1.ReadOnly = True
End Sub

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...