WPF Datagrid将第二个数据库表显示为ComboBox选项

时间:2018-05-15 15:59:34

标签: c# sql wpf data-binding datagrid

我在我的数据库中添加了第二个表,其中包含我希望在新列中的数据网格的每一行的组合框中看到的不同选项。每个选项都有一个与之关联的键,它与我主表中的一列相匹配,这是一个0到8的值。我有2个问题,其中一个我已经解决了:

  1. 当网格加载时,我希望组合框列显示与每行[Status]键对应的[Description]。这很有效。

  2. 我希望用户选择[描述]单元格并打开一个下拉列表,打开所有可能的[描述]选项,以便他可以更改项目的状态。

  3. 例如,如果某个组件处于暂停状态,则用户需要在网格中选择该组件,并在状态列的下拉列表中选择“暂停”。

    状态正确显示,但下拉列表不会填充CNCComponentStatus表中的8个选项。我愿意打赌我没有在SqlDataAdapter中正确填充第二个表的数据集。那或我没有正确使用SelectedItem / ItemSource / SelectedValuePath。

    以下是网格grid的屏幕截图 这是我的数据结构structure

    这些是状态选项: enter image description here

    这是datagrid的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
    

    感谢您的时间,对于极端的细节感到抱歉。

    编辑: 这是我如何尝试填充组合框,因为我没有正确绑定。虽然我不太明白如何只显示一列而不是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 :(得分:2)

我想,这就是组合框应该看起来像什么的。不需要x:Name属性。我怀疑是否也需要IsEditable。

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

SelectedValuePathDisplayMemberPath是字符串。它们是填充ComboBox的数据行中的列的名称(如果使用常规C#类实例填充它们,则它们将是项类的属性的名称)。您试图将这些属性绑定到您没有的视图模型的属性,但即使您有一个属性,也不会具有这些属性。但是,绑定的概念和它的作用一开始可能会非常滑。

我几乎告诉你read the documentation on SelectedValuePath,但文档已经修改,现在基本没有意义。 DisplayMemberPath is better

第二:你应该有一个viewmodel。缺少视图模型会使一切变得更加困难。但是你没有viewmodel。

您需要做的是从数据库中获取您想要的内容,并将其放在某个可以绑定组合框的地方。

缺少一个viewmodel作为该集合的自然之家,我们将通过在窗口的Resources中创建一个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 id值的外键,我猜它可能被称为{{ 1}}。

所以我们想要发生的事情是:假设你有两个项目:

Status

item 0: Status = 1 Description = Dog item 1: Status = 2 Description = Cat 表示项目0将显示为“Dog”,即其Description属性的值。出于同样的原因,项目1将显示为“Cat”。

DisplayMemberPath="Description"表示当绑定将SelectedValue设置为SelectedValuePath="Status"时,组合框将查看其items集合,以查找2属性等于Status的项目,然后选择该项目。如果我们设置2,它会查找具有名为SelectedValuePath="Fred"的属性等于Fred的项目。

同样,如果用户自己更改选择,则会采用另一种方式:假设用户选择项目0,因此ComboBox会查询自己的2,看到“状态”,并获得{{1所选项的属性值(如果有)。对于第0项,即SelectedValuePath。然后组合框会将Status的值分配给它自己的1属性。

1上的绑定将收到SelectedValue已更改的通知,它将获取新值并更新它所绑定的数据库行列(也称为“状态”,在此案件)。

SelectedValue是一个坚持并做事的对象。对于“任务”来说,这不是一个奇特的词。

SelectedValue