JSON.NET对象的数据绑定:如何实现?

时间:2017-01-08 11:04:46

标签: json vb.net winforms data-binding datagridview

我的应用程序处理了很多返回JSON数据的HTTP请求。我使用JSON.NET库来处理它。

我需要在Winforms数据绑定控件中显示这些数据(主要是ComboBoxDataGridView)。目前不打算进行数据编辑,只需要以用户友好的方式显示数据。

我写了一个即兴转换例程,将IEnumerable(Of JToken)转换为DataTable

Module JsonAsDataTable
    <Runtime.CompilerServices.Extension> Public Function ToDataTable(ByVal jtokens As IEnumerable(Of JToken), Optional ByVal trim_object_columns As Boolean = False, Optional ByVal castToCLRtypes As Boolean = False, Optional ByVal orderBy As String = Nothing) As DataTable
        Dim dt As New DataTable, sdt As DataTable, dr, sdr As DataRow, dateproperty As Date
        If jtokens IsNot Nothing Then
            For Each jt In jtokens
                dr = dt.NewRow
                For Each jp In jt.Children(Of JProperty)
                    sdt = Nothing
                    If Not dt.Columns.Contains(jp.Name) Then dt.Columns.Add(jp.Name, IIf(castToCLRtypes, GetType(Object), GetType(JToken)))
                    If jp.Value.Type = JTokenType.Object AndAlso jp.Value.Children.Count = 1 AndAlso jp.Value.First.Type = JTokenType.Property AndAlso DirectCast(jp.Value.First, JProperty).Name = "date" Then
                        If Date.TryParse(DirectCast(jp.Value.First, JProperty).Value, dateproperty) Then
                            dr.SetField(jp.Name, New JValue(dateproperty))
                        Else
                            dr.SetField(jp.Name, JValue.CreateNull)
                        End If
                    Else
                        dr.SetField(jp.Name, jp.Value)
                        If jp.Value.Type = JTokenType.Object Then
                            sdt = AsDataTable({jp.Value}, trim_object_columns)
                        ElseIf jp.Value.Type = JTokenType.Array Then
                            sdt = AsDataTable(jp.Value, trim_object_columns)
                        End If
                        If sdt IsNot Nothing Then
                            sdr = sdt.Select.FirstOrDefault
                            For Each sdc As DataColumn In sdt.Columns
                                If Not dt.Columns.Contains(jp.Name & "." & sdc.ColumnName) Then dt.Columns.Add(jp.Name & "." & sdc.ColumnName, GetType(Object))
                                If sdr IsNot Nothing Then dr.SetField(jp.Name & "." & sdc.ColumnName, sdr(sdc.ColumnName))
                            Next
                            If trim_object_columns Then dt.Columns.Remove(jp.Name)
                        End If
                    End If
                Next
                dt.Rows.Add(dr)
            Next
            If castToCLRtypes Then
                For Each drow In dt.Select
                    For Each dcol As DataColumn In dt.Columns
                        If TypeOf drow(dcol) Is JToken Then drow(dcol) = ToField(drow(dcol))
                    Next
                Next
            End If
            If dt.Rows.Count > 0 AndAlso Not String.IsNullOrEmpty(orderBy) Then
                dt = dt.Select("", orderBy).CopyToDataTable
            End If
        End If
        Return dt
    End Function
    <Runtime.CompilerServices.Extension> Friend Function ToField(token As JToken) As Object
        If token Is Nothing Then Return Nothing
        Select Case token.Type
            Case JTokenType.Boolean
                Return token.Value(Of Boolean)
            Case JTokenType.Bytes
                Return token.Value(Of Byte())
            Case JTokenType.Date
                Return token.Value(Of Date)
            Case JTokenType.Float
                Return token.Value(Of Double)
            Case JTokenType.Guid
                Return token.Value(Of Guid)
            Case JTokenType.Integer
                Return token.Value(Of Integer)
            Case JTokenType.Null
                Return Nothing
            Case JTokenType.Property
                Return ExtractObjectFrom(CType(token, JProperty).Value)
            Case JTokenType.String
                Return token.Value(Of String)
            Case JTokenType.TimeSpan
                Return token.Value(Of TimeSpan)
            Case JTokenType.Uri
                Return token.Value(Of Uri)
            Case Else
                Return token.ToString
        End Select
    End Function
End Module

现在我知道我的解决方案既不干净也不可靠。这只是我想到的第一件事,就是用DataGridView显示事物,用户可以通过点击列标题对数据进行排序,而JToken的简单数组是不允许的。

因此,我想编写一个包装JToken对象的自定义类,也许是一个Collection类,以DataGridView容易理解和处理的方式列出它们,实现排序等功能(这对我来说是必不可少的)和过滤(这对于成就者来说是额外的奖励)。

我的问题是:这是 这些类应该实现的最小接口

1 个答案:

答案 0 :(得分:1)

使用List<T>等通用集合实现列的排序并不容易。通常IList<T>ICollection<T>足以从Collection端绑定到GridView。您的对象不需要实现任何要在GridView中显示的接口。对于排序,您可能需要ICompareable<T>。问题是对Collection进行排序并不像对DataTable进行排序那么容易。 GridView组件在这里非常差。在这个link上,您会发现许多建议如何解决使用集合进行排序的问题。示例是C#,但应该是适应性的。我希望这可以帮到你。