我的应用程序处理了很多返回JSON数据的HTTP请求。我使用JSON.NET库来处理它。
我需要在Winforms数据绑定控件中显示这些数据(主要是ComboBox
和DataGridView
)。目前不打算进行数据编辑,只需要以用户友好的方式显示数据。
我写了一个即兴转换例程,将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
容易理解和处理的方式列出它们,实现排序等功能(这对我来说是必不可少的)和过滤(这对于成就者来说是额外的奖励)。
我的问题是:这是 这些类应该实现的最小接口?
答案 0 :(得分:1)
使用List<T>
等通用集合实现列的排序并不容易。通常IList<T>
或ICollection<T>
足以从Collection端绑定到GridView。您的对象不需要实现任何要在GridView中显示的接口。对于排序,您可能需要ICompareable<T>
。问题是对Collection进行排序并不像对DataTable进行排序那么容易。 GridView组件在这里非常差。在这个link上,您会发现许多建议如何解决使用集合进行排序的问题。示例是C#,但应该是适应性的。我希望这可以帮到你。