【问题标题】:Search content of a JSON file with output in a DataGridView在 DataGridView 中搜索带有输出的 JSON 文件的内容
【发布时间】:2022-10-21 10:52:13
【问题描述】:

该窗体有一个文本字段和一个 DataGridView。需要在 DataGridView 中不显示 JSON 文件的全部内容的情况下,搜索 JSON 文件的内容并将搜索结果显示在 DataGridView 中。
您需要按 UserName 标记进行搜索。您需要开始在文本字段中输入名字或姓氏,并在 DataGridView 中显示找到的结果。

我知道如何在 DataGridView 中读取文本文件:

Imports System.IO
Imports Newtonsoft.Json

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim result = JsonConvert.DeserializeObject(Of List(Of Users))(File.ReadAllText("D:\Users.json"))
        DataGridView1.DataSource = result
    End Sub

      Public Class Users
        Public Property ID() As Integer
        Public Property UserName() As String
        Public Property Login() As String
        Public Property Title() As String
        Public Property Dep() As String
        Public Property Mail() As String
        Public Property Phone() As String
    End Class
End Class

我也知道如何进行文件搜索。仅出于某种原因显示结果 - 找到的第一个元素:

Dim json As String = File.ReadAllText("D:\Users.json")
Dim objectList = JsonConvert.DeserializeObject(Of List(Of Users))(json)
Dim foundItem = objectList.Where(Function(underscore) underscore.UserName.Contains("Tom")).FirstOrDefault()

If foundItem IsNot Nothing Then
    MessageBox.Show(foundItem.UserName)
Else
    MsgBox("none")
End If

以及 json 文件本身的实际内容:

[
{
"id":"1",
"UserName":"Fred Smith",
"Login":"f.smith",
"Title":"engineer",
"Dep":"IT infrastcomcture",
"Mail":"f.smith@domain.com",
"Phone":"111",
},
{
"id":"2",
"UserName":"Ben Taylor",
"Login":"b.taylor",
"Title":"programmer",
"Dep":"IT infrastcomcture",
"Mail":"b.taylor@domain.com",
"Phone":"100",
},
{
"id":"3",
"UserName":"Steve Harris",
"Login":"s.harris",
"Title":"System Administrator",
"Dep":"IT infrastcomcture",
"Mail":"s.harris@domain.com",
"Phone":"263",
},
{
"id":"4",
"UserName":"Tom Walker",
"Login":"t.walker",
"Title":"engineer",
"Dep":"IT infrastcomcture",
"Mail":"t.walker@domain.com",
"Phone":"263",
},
{
"id":"5",
"UserName":"Tom Davis",
"Login":"t.davis",
"Title":"engineer",
"Dep":"IT infrastcomcture",
"Mail":"t.davis@domain.com",
"Phone":"200",
},
{
"id":"6",
"UserName":"Ben Walker",
"Login":"b.walker",
"Title":"System Administrator",
"Dep":"IT infrastcomcture",
"Mail":"b.walker@domain.com",
"Phone":"167",
},
]

【问题讨论】:

  • .FirstOrDefault().Where() 子句之后有 .FirstOrDefault(),因此该查询仅返回找到的第一个匹配项。 -- 请注意,紧随其后的If 条件期待这种结果。 -- 您通常过滤数据源以仅显示符合某些条件的结果。我建议使用 BindingSource,因为它也可以用作过滤器。
  • 如果您以代码的形式提供示例,我将不胜感激。提前致谢
  • 你能澄清这是否是某种任务,因为 - 正如它所写的那样 - 它看起来像一个。没关系,就其本身而言,问题写得很好,但如果是这样的话,您可能需要使用特定的工具。是否包含 BindingSource?
  • 是否可以在不绑定到 BindingSource 的情况下执行此操作?由于数据显示模式可能会改变。这不是一份工作,这是给你自己的。
  • BindingSource 与数据的呈现方式之间没有关系。

标签: json .net vb.net winforms datagridview


【解决方案1】:

需要注意的几点:

  • 此处显示的 JSON 表示一个对象数组,它们都具有相同的属性。它可以被认为是一个数组记录或者.
  • 您需要反序列化此 JSON,在 DataGridView 中显示结果,并允许用户过滤并可能对数据进行排序。

您目前正在将此 JSON 反序列化为简单的类对象集合,这非常好。如果你想过滤和排序这个集合,它可能会变得有点复杂,因为一个简单的List<T> 本身并不支持它。 BindingList 也没有。
您应该在处理对象列表的类中实现IBindingListView 接口,并且很可能还应该在基类(您当前的Users 类)中实现INotifyPropertyChanged 接口。
或者改用 ORM / Mini-ORM。

有一个已经构建(和测试)的类型已经实现了所有这些特性,DataTable 类。
因为,如前所述,您的 JSON 实际上是一个表(一个数组记录),将其反序列化为 DataTable 非常简单。只是:

Dim dt = JsonConvert.DeserializeObject(Of DataTable)(json) 

DataTable 类已经允许过滤,设置它的DefaultView.RowFilter 属性和排序,设置它的DefaultView.Sort 属性。

尽管如此,我建议使用BindingSource 作为调解员在 DataTable 和 UI 之间。
这个工具非常有用,因为它提供了对数据源进行过滤和排序的常用方法,前提是数据源实际上具有这些功能。
使用 BindingSource,无论数据源是什么,您始终使用相同的方法。
它还会生成一些有用的事件,如ListChangedAddingNewCurrentChanged 事件等等。
ListChanged 事件还提供指定更改类型的参数。

使用 BindingSource,如果数据已更改,则序列化回 JSON:

[BindingSource].EndEdit()
Dim json = JsonConvert.SerializeObject([BindingSource].DataSource, Formatting.Indented)

在示例代码中,使用了这些对象(参见视觉示例):

  • UsersSource: BindingSource 对象
  • tBoxFilterUser:一个 TextBox 控件,使用 UserName 属性过滤数据
  • tBoxFilterTitle:一个 TextBox 控件,使用 Title 属性过滤数据
  • btnRemoveFilter:用于移除当前过滤器的按钮控件
  • dgv: 一个 DataGridView 控件

Public Class SomeForm

    Private UsersSource As New BindingSource()
    ' Current filters
    Private UserNameFilter As String = "UserName LIKE '%%'"
    Private UserTitleFilter As String = "Title LIKE '%%'"

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)

        Dim json = File.ReadAllText("D:Users.json")
        Dim dt = JsonConvert.DeserializeObject(Of DataTable)(json)
        dt.AcceptChanges()
        UsersSource.DataSource = dt
        dgv.DataSource = UsersSource
    End Sub

    Private Sub tBoxFilterUser_TextChanged(sender As Object, e As EventArgs) Handles tBoxFilterUser.TextChanged
        Dim tbox = DirectCast(sender, TextBox)
        UserNameFilter = $"UserName LIKE '%{tbox.Text}%'"
        UsersSource.Filter = $"{UserNameFilter} AND {UserTitleFilter}"
    End Sub

    Private Sub tBoxFilterTitle_TextChanged(sender As Object, e As EventArgs) Handles tBoxFilterTitle.TextChanged
        Dim tbox = DirectCast(sender, TextBox)
        UserTitleFilter = $"Title LIKE '%{tbox.Text}%'"
        UsersSource.Filter = $"{UserNameFilter} AND {UserTitleFilter}"
    End Sub

    Private Sub btnRemoveFilter_Click(sender As Object, e As EventArgs) Handles btnRemoveFilter.Click
        tBoxFilterUser.Clear()
        tBoxFilterTitle.Clear()
        UsersSource.RemoveFilter()
    End Sub
End Class

这是它的工作原理:

【讨论】:

  • 很酷。非常感谢这个例子!
  • 好吧,这是一个有效的例子:) 试一试,看看这是否适合你。
  • 当然,这已经是另一个话题了,但是你能告诉我在从 json 文件中添加数据之前如何设置列类型吗?
  • 你能指定你需要解决什么样的问题(相对于你在这里发布的内容)?您是否需要更改 JSON 中的属性类型,或者之后更改列的类型?在这种情况下,为什么? -- 如果对 cme​​ts 的解释太长,请发布一个新问题并指出该问题作为参考。
  • 您是指数据表中列的类型吗?当 DataTable 还没有数据时,您可以更改列的类型。之后不会,除非您构建一个新的 DataTable 并将数据转换为使用原始 DataTable 作为源的不同类型。但是您可以更改 JSON 中的属性类型。例如,现在id 是一个字符串类型。您可以将其更改为 Long 删除值上的双引号。 ——你需要具体,描述你想要改变什么,改变什么,可能是为什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-09
  • 2019-05-29
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 2014-12-14
  • 2016-07-24
相关资源
最近更新 更多