Display images in a DataGridView column using JSON objects as DataSource

≡放荡痞女 提交于 2020-01-06 03:16:18

问题


How would I go about formatting a DataGridView column to show an image from a URL instead of the URL itself as string.

Example of what the DataGridView currently looks like:

I currently have the following code:

 DataGridView1.DataSource = Tesco.uk.ghs.products.results  

Here I am binding the JSON I have to datagridview1.
This works (even though as you can see from the screenshot it seems to miss out the Description Column for some reason).

I have also tried using the class DataGridViewImageColumn however I cannot get it to actually "convert" the column to be an image column.

JSON:

Public Class Totals
   Public Property all As Integer
   Public Property [new] As Integer
   Public Property offer As Integer
End Class

Public Class Result
   Public Property image As String
   Public Property superDepartment As String
   Public Property tpnb As Integer
   Public Property ContentsMeasureType As String
   Public Property name As String
   Public Property UnitOfSale As Integer
   Public Property description As String()
   Public Property AverageSellingUnitWeight As Double
   Public Property UnitQuantity As String
   Public Property id As Integer
   Public Property ContentsQuantity As Double
   Public Property department As String
   Public Property price As Double
   Public Property unitprice As Double
End Class

Public Class Products
   Public Property input_query As String
   Public Property output_query As String
   Public Property queryPhase As String
   Public Property totals As Totals
   Public Property config As String
   Public Property results As Result()
   Public Property suggestions As Object()
End Class

Public Class Ghs
   Public Property products As Products
End Class

Public Class Uk
   Public Property ghs As Ghs
End Class

Public Class JSON
   Public Property uk As Uk
End Class

回答1:


Note: This question has a follow-up here:
Copy selected checkbox rows from DGV to DGV2 including image column


You need to download the images after the JSON has been deserialized into your class object. You can and add a new public property of Type Bitmap to the internal Result class, which will be used to present the Image referenced by the URI found in the JSON.

To aquire the Images, you need a method that takes the resource URI and downloads it from the remote machine. I added a public method to the Products class, which references all the objects that contain a URI reference:
after the JSON has been parsed successfully, the Results property will reference all the Result classes. Each Result class will reference the Bitmap URI in the ProductImage Property.

Using a WebClient class, we can use these references to download the Images and add them to a Property of Type Bitmap.
We also need to instruct the JSON parser to ignore this Property, since it's not part of the JSON object.
This can be done adding a <JsonIgnore> attribute to the property.

Rename the RootObject (named JSON in your class definition) to Root:

Also, all the classes you're showing here are added to a Parent class named ProductsQuery, used as a container for all the class objects.

Public Class Root
   Public Property uk As Uk
End Class

Deserialize the JSON with JsonConvert.DeserializeObject:

Dim JSONObject As String = File.ReadAllText("[Source Txt]")
Dim JsonPost As ProductsQuery.Root = JsonConvert.DeserializeObject(Of ProductsQuery.Root)(JSONObject)

Use the newly added public method to download the images:

JsonPost.uk.ghs.Products.LoadImages()

Prepare the DataGridViewImageColumn that will show the Images:
Edit: also insert a DataGridViewCheckBoxColumn.

Dim DGVCheckBoxCol As DataGridViewCheckBoxColumn = New DataGridViewCheckBoxColumn(False) With {
    .AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCellsExceptHeader,
    .DisplayIndex = 0,
    .HeaderText = "",
    .Name = "Select"
}

Dim DGVImageCol As DataGridViewImageColumn = New DataGridViewImageColumn(False) With {
    .AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCellsExceptHeader,
    .DataPropertyName = "Image",
    .DisplayIndex = 1,
    .FillWeight = 1,
    .HeaderText = "Image",
    .ImageLayout = DataGridViewImageCellLayout.Normal,
    .Name = "Image",
    .ValuesAreIcons = False
}

Then, set the DataGridView DataSource and hide the Column that contains the Image URI, which is not really useful here. Also, call the AutoResizeRows method to set the size of the rows to better present the Image:

DataGridView1.DataSource = Nothing 
DataGridView1.Columns.Clear()

DataGridView1.Columns.Insert(0, DGVCheckBoxCol)
DataGridView1.Columns.Insert(1, DGVImageCol)
DataGridView1.DataSource = JsonPost.uk.ghs.Products.Results
DataGridView1.Columns(2).Visible = False
DataGridView1.AutoResizeRows()

Result:

The modified classes:

Note:
The description property is an array of strings, which the DGV refuses to show as it is. I've called it RawDescription and I added a new property (Description) of type String - with an <JsonIgnore> attribute - in the Result class, that will contain the flattened string.

Imports System.IO
Imports System.Net
Imports Newtonsoft.Json

Public Class ProductsQuery

    Public Class Root
        Public Property uk As Uk
    End Class

    Public Class Uk
        Public Property ghs As Ghs
    End Class

    Public Class Ghs
        Public Property products As Products
    End Class

    Public Class Products
        Public Property input_query As String
        Public Property output_query As String
        Public Property filters As Filters
        Public Property queryPhase As String
        Public Property totals As Totals
        Public Property config As String

        <JsonProperty("results")>
        Public Property Results As Result()
        Public Property suggestions As Object()

        Public Sub LoadImages()
            Using client As WebClient = New WebClient()
                For Each result As Result In Results
                    Dim bitmapBytes = client.DownloadData(result.ProductImage)
                    Using ms As MemoryStream = New MemoryStream(bitmapBytes)
                        ms.Position = 0
                        result.Image = CType(Image.FromStream(ms).Clone(), Bitmap)
                    End Using
                    result.ProductDescription = result.RawDescription(0)
                Next
            End Using
        End Sub
    End Class

    Public Class Filters
    End Class

    Public Class Totals
        Public Property all As Integer
        <JsonProperty("new")>
        Public Property NewProducts As Integer
        Public Property offer As Integer
    End Class

    Public Class Result

        <JsonIgnore>
        Public Property Image As Bitmap

        <JsonProperty("image")>
        Public Property ProductImage As String

        <JsonProperty("superDepartment")>
        Public Property SuperDepartment As String
        Public Property tpnb As Integer
        Public Property ContentsMeasureType As String

        <JsonProperty("name")>
        Public Property Name As String
        Public Property UnitOfSale As Integer

        <JsonIgnore>
        Public Property Description As String

        <JsonProperty("description")>
        Public Property RawDescription As String()
        Public Property AverageSellingUnitWeight As Double
        Public Property UnitQuantity As String
        Public Property id As Integer
        Public Property ContentsQuantity As Double

        <JsonProperty("department")>
        Public Property Department As String

        <JsonProperty("price")>
        Public Property Price As Double

        <JsonProperty("unitprice")>
        Public Property Unitprice As Double
    End Class
End Class



回答2:


You have to first convert the column where you want the images as an Image column.

You can do it in the properties of that datagridview OR programatically when you create the datagridview and you add your columns to it :

 Dim imgColumn as new DataGridViewImageColumn
 DataGridView1.Columns.Add(imgColumn)

Once you've added the column/changed the type of the column you could then convert each cell in that column into a bitmap image:

It could look roughly like this (replace colindex with the index number of your image column for example your imgColumn we declared above):

 Dim currRow as Int = 0
 For Each row As DataGridViewRow In DataGridView1.Rows

            Dim img = new Bitmap(DataGridView1.Item(colindex, currRow).value);

            DataGridView1.Item(colindex, currRow).value = img

            currRow = currRow + 1


  Next

Reference here



来源:https://stackoverflow.com/questions/54204643/display-images-in-a-datagridview-column-using-json-objects-as-datasource

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!