WPF Datagrid, показывающий вторую таблицу БД в качестве параметров ComboBox - PullRequest
0 голосов
/ 15 мая 2018

Я добавил в свою базу данных вторую таблицу, которая содержит различные параметры, которые я хочу видеть в поле со списком для каждой строки моей таблицы данных в новом столбце. С каждым параметром связан ключ, который соответствует столбцу в моей основной таблице, значение которого находится в диапазоне от 0 до 8. У меня есть 2 проблемы, одну из которых я решил:

  1. Когда сетка загружается, я хочу, чтобы в столбце комбинированного списка отображалось [Описание], которое соответствует клавише [Статус] каждой строки. Это работает.

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

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

Статус отображается правильно, но раскрывающийся список не заполняется 8 опциями из таблицы CNCComponentStatus. Я готов поспорить, что я не правильно заполняю набор данных второй таблицей в SqlDataAdapter. Это или я неправильно использую SelectedItem / ItemSource / SelectedValuePath.

Вот скриншот сетки grid Вот моя структура данных structure

Это параметры статуса: enter image description here

Вот xaml для сетки данных (только соответствующие части):

<DataGrid Name="dataGrid1" ItemsSource="{Binding Path=test_3DimensionalDB}" AutoGenerateColumns="False">
<DataGridTemplateColumn x:Name="StatusColumn" Header="Status" Width="*" IsReadOnly="False">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock x:Name="cboStatus" Text="{Binding Path=Description, Mode=TwoWay}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox x:Name="StatusCombo" IsEditable="True" SelectedValuePath="{Binding Status}" DisplayMemberPath="{Binding Description}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

А вот метод, который захватывает данные:

 Private Sub SelectQuery(ByVal company As String, ByVal status As String, ByVal component As String)

    Dim com As String = "SELECT tmfCNCComponent_threed.[CNCComponentKey]
    ,tmfCNCComponent_threed.[CompanyID]
    ,tmfCNCComponent_threed.[JobNumber]
    ,tmfCNCComponent_threed.[LogNumber]
    ,tmfCNCComponent_threed.[Customer]
    ,tmfCNCComponent_threed.[DueDate]
    ,tmfCNCComponent_threed.[JobLeader]
    ,tmfCNCComponent_threed.[CADProgrammer]
    ,tmfCNCComponent_threed.[Salesperson]
    ,tmfCNCComponent_threed.[CNCProgrammer]
    ,tmfCNCComponent_threed.[ComponentDescription]
    ,tmfCNCComponent_threed.[ComponentFilePath]
    ,tmfCNCComponent_threed.[Material]
    ,tmfCNCComponent_threed.[ComponentSizeX]
    ,tmfCNCComponent_threed.[ComponentSizeY]
    ,tmfCNCComponent_threed.[ComponentSizeZ]
    ,tmfCNCComponent_threed.[QuantityShown]
    ,tmfCNCComponent_threed.[QuantityMirror]
    ,tmfCNCComponent_threed.[UpdateTime]
    ,tmfCNCComponent_threed.[Status]
    ,tmfCNCComponent_threed.[ProgStarted]
    ,tmfCNCComponentStatus_threed.[Description]
    FROM [test_3DimensionalDB].[dbo].[tmfCNCComponent_threed]
    INNER JOIN tmfCNCComponentStatus_threed
    ON tmfCNCComponent_threed.Status = tmfCNCComponentStatus_threed.CNCComponentStatusKey 
    WHERE [ComponentDescription] " & component & " 'trode%' AND [CompanyID]='" & company & "' AND [Status]" & status & "ORDER BY [UpdateTime] DESC"

    Dim Adpt As New SqlDataAdapter(com, con)
    con.Open()
    Dim ds As New DataSet()
    Adpt.Fill(ds, "dbo.tmfCNCComponent_threed")

    dataGrid1.ItemsSource = ds.Tables("dbo.tmfCNCComponent_threed").DefaultView

    con.Close()

    RowCount()
    searchBox.Clear()

End Sub

Спасибо за ваше время, извините за крайнюю детализацию.

EDIT: Вот как я могу попытаться заполнить поле со списком, так как я не связываюсь должным образом. Хотя я не совсем понимаю, как показать только один столбец вместо DefaultView. Кроме того, «StatusCombo» недоступен из-за уровня защиты?

    Dim com2 As String = "SELECT * FROM tmfCNCComponentStatus_threed"
    Dim AdptStatus As New SqlDataAdapter(com2, con)
    AdptStatus.Fill(ds, "dbo.tmfCNCComponentStatus_threed")
    StatusCombo.ItemsSource = ds.Tables("dbo.tmfCNCComponentStatus_threed").DefaultView

1 Ответ

0 голосов
/ 15 мая 2018

Вот как должен выглядеть этот комбобокс, я думаю.Свойство x: Name не требуется.Сомневаюсь, что IsEditable тоже нужен.

<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
        <ComboBox 
            IsEditable="True" 
            SelectedValuePath="Status" 
            DisplayMemberPath="Description" 
            SelectedValue="{Binding Status}"
            />
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

SelectedValuePath и DisplayMemberPath являются строками.Это имена столбцов в строках данных, которые заполняют ComboBox (если вы заполните его обычными экземплярами класса C #, они вместо этого будут именами свойств класса элемента).Вы пытались привязать эти свойства к свойствам модели представления, которой у вас нет, но даже если бы она у вас была, у них не было бы этих свойств.Но понятие о том, что такое связывание и что оно делает, может поначалу быть странно скользким.

Я почти сказал вам прочитать документацию по SelectedValuePath , но документация была пересмотрена и теперь по сути бессмысленна. DisplayMemberPath лучше .

Второе: у вас должна быть модель представления.Отсутствие модели представления усложняет все.Но у вас нет модели представления.

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

Если у нас нет модели представления, которая могла бы служить естественным домом для этой коллекции, мы сделаем это, создав CollectionViewSource в ресурсах вашего окна.

<Window
    x:Class="blah blah"
    ...stuff...
    >
    <Window.Resources>
        <CollectionViewSource
            x:Key="StatusItems"
            />
    </Window.Resources>

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

<ComboBox 
    x:Name="StatusCombo" 
    SelectedValuePath="Status" 
    DisplayMemberPath="Description" 
    ItemsSource="{Binding Source={StaticResource StatusItems}}"
    />

Но наш CollectionViewSource пуст.Так что нам придется как-то его заселить.Мы будем делать это всякий раз, когда вы выполняете запрос к базе данных.

Dim statusCVS As CollectionViewSource = FindResource("StatusItems")

Dim com2 As String = "SELECT * FROM tmfCNCComponentStatus_threed"
Dim AdptStatus As New SqlDataAdapter(com2, con)
AdptStatus.Fill(ds, "dbo.tmfCNCComponentStatus_threed")

Dim statusRows = ds.Tables("dbo.tmfCNCComponentStatus_threed").Rows
Dim statuses As New List(Of Object)

For Each row As DataRow In statusRows
    statuses.Add(New With {
            .Status = CInt(row("CNCComponentStatusKey")),
            .Description = CStr(row("Description"))
        })
Next

statusCVS.Source = statuses

Это было бы лучше, чем цикл, если он работает:

Dim statuses = From row In ds.Tables("dbo.tmfCNCComponentStatus_threed")
               .Rows.Cast(Of DataRow)
               Select New With {
                    .Status = CInt(row("CNCComponentStatusKey")),
                    .Description = CStr(row("Description"))
                }

statusCVS.Source = statuses

ОК, теперь у нас есть эта часть:

    SelectedValue="{Binding Status}"

Япредполагая, что test_3DimensionalDB (действительно ли заполнена ваша DataGrid?) должен иметь некоторый столбец, который является внешним ключом к значению идентификатора состояния в комбо, и я предполагаю, что он может называться Status.

Итак, что мы хотим сделать, это: скажем, у вас есть два элемента:

item 0:
    Status = 1
    Description = Dog
item 1:
    Status = 2
    Description = Cat

DisplayMemberPath="Description" означает, что элемент 0 будет отображаться как «Собака», значение его свойства Description,Элемент 1 будет отображаться как «Кошка» по той же причине.

SelectedValuePath="Status" означает, что когда привязка устанавливает SelectedValue в 2, комбинированный список просматривает свою коллекцию элементов, чтобы найти элемент со свойством Status, равным 2, и выбирает этот элемент.,Если мы установим SelectedValuePath="Fred", он будет искать элемент со свойством с именем Fred, равным 2.

Аналогично, если пользователь сам изменяет выбор, он идет другим путем: скажем, пользователь выбирает элемент 0, поэтому ComboBox обращается к своему собственному SelectedValuePath, видит «Status» и получает Status значение свойства (если есть) выбранного элемента.Для пункта 0 это 1.Затем комбинированный список присваивает это значение 1 своему собственному свойству SelectedValue.

Привязка к SelectedValue получит уведомление об изменении SelectedValue, получит новое значение и обновит столбец строки базы данных, к которой она привязана (в данном случае также называется «Статус»).).

Binding - это объект, который торчит и делает вещи.Это не модное слово для «назначения».

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