Fastest way to save and restore datagrid view contents

Hobbyist_programmer 621 Reputation points
2021-04-28T18:57:16.963+00:00

Hallo,

I have lots of datagrid view and all of them bound to list of objects , one example is shown below, where Qty and remarks are the input fields and not necessarily all of them will be filled. I want to save rows where there is a Qty. I dont want to save the complete row, instead only the ID , Qty and Remarks.

92198-image.png

At present I filter the Qty in the list using LINQ and looping it and save the row contents as List of strings like this "ID/Qty/Remarks" . To restore, i split the string and restore it to the List. It works without any problem.

Is there any alternative or better approach to it in terms of performance?

Thanks

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
1,845 questions
{count} votes

Accepted answer
  1. Karen Payne MVP 29,236 Reputation points MVP
    2021-04-29T12:20:29.1+00:00

    Hello,

    The following uses a class named Product, if using a DataTable or DataSet then adjustments are needed. The code finds rows with a Qty not null (Nothing)

    To save and read back a List(Of ProductSave) use Json.net (the link shows serialize and deserialize in C# but is easy enough to convert to VB, if you get stuck I can help) via this package.

    Product class

    Public Class Product  
        Public Property Id() As Integer  
        Public Property Description() As String  
        Public Property Qty() As Integer?  
        Public Property UnitCost() As Decimal  
      
        Public ReadOnly Property Total() As Decimal  
            Get  
                If Qty.HasValue Then  
                    Return CDec(Qty * UnitCost)  
                Else  
                    Return 0  
                End If  
            End Get  
      
        End Property  
      
        Public Property Remarks() As String  
      
    End Class  
    

    Class to save rows

    Public Class ProductSave  
        Public Property Id() As Integer  
        Public Property Qty() As Integer?  
        Public Property Remarks() As String  
    End Class  
    

    Mock up data

    Public Class MockedData  
        Public Shared Function Products() As List(Of Product)  
            Dim productList = New List(Of Product)()  
            productList.Add(New Product() With {  
                                .Id = 1,  
                                .Description = "Item1",  
                                .Qty = Nothing,  
                                .UnitCost = 2.99D,  
                                .Remarks = "Item 1 remarks"  
                                })  
            productList.Add(New Product() With {  
                                .Id = 2,  
                                .Description = "Item2",  
                                .Qty = 3,  
                                .UnitCost = 10.99D,  
                                .Remarks = "Item 2 remarks"  
                                })  
            productList.Add(New Product() With {  
                                .Id = 3,  
                                .Description = "Item3",  
                                .Qty = Nothing,  
                                .UnitCost = 10.99D,  
                                .Remarks = "Item 3 remarks"  
                                })  
            productList.Add(New Product() With {  
                                .Id = 4,  
                                .Description = "Item3",  
                                .Qty = 8,  
                                .UnitCost = 1.99D,  
                                .Remarks = "Item 4 remarks"  
                                })  
            productList.Add(New Product() With {  
                                .Id = 5,  
                                .Description = "Item3",  
                                .Qty = 8,  
                                .UnitCost = 1.99D,  
                                .Remarks = ""  
                                })  
            Return productList  
        End Function  
    End Class  
    

    Form, one DataGridView, one Button

    Public Class MainForm  
        Private _bindingSource As New BindingSource()  
      
        Private Sub MainForm_Shown(sender As Object, e As EventArgs) Handles Me.Shown  
            DataGridView1.AllowUserToAddRows = False  
            _bindingSource.DataSource = MockedData.Products()  
            DataGridView1.DataSource = _bindingSource  
        End Sub  
      
        Private Sub GetRowsToSaveButton_Click(sender As Object, e As EventArgs) Handles GetRowsToSaveButton.Click  
      
            Dim results = DirectCast(_bindingSource.DataSource, List(Of Product)).  
                    Where(Function(prod) prod.Qty.HasValue AndAlso Not String.IsNullOrWhiteSpace(prod.Remarks)).  
                    ToList()  
      
            If results.Count <= 0 Then  
                Return  
            End If  
      
            Dim saved = New List(Of ProductSave)  
      
            For Each product In results  
                saved.Add(New ProductSave() With {.Id = product.Id, .Qty = product.Qty, .Remarks = product.Remarks})  
            Next  
        End Sub  
      
        Private Sub SaveTo(sender As List(Of ProductSave))  
            ' Save information to say a .json file using json.net NuGet package  
        End Sub  
        Private Function GetSaved() As List(Of ProductSave)  
            ' read from .json file created in SaveTo method above  
            Throw New NotImplementedException  
        End Function  
    End Class  
    

    Edit. I missed one part

    Private Sub GetRowsToSaveButton_Click(sender As Object, e As EventArgs) Handles GetRowsToSaveButton.Click  
      
        Dim results = DirectCast(_bindingSource.DataSource, List(Of Product)).  
                Where(Function(prod) prod.Qty.HasValue AndAlso Not String.IsNullOrWhiteSpace(prod.Remarks)).  
                ToList()  
      
        If results.Count <= 0 Then  
            Return  
        End If  
      
        Dim saved = New List(Of ProductSave)  
      
        For Each product In results  
            saved.Add(New ProductSave() With {.Id = product.Id, .Qty = product.Qty, .Remarks = product.Remarks})  
        Next  
      
        SaveTo(saved)  
    End Sub  
    

    ---
    92714-kpmvp.png

    No comments

3 additional answers

Sort by: Most helpful
  1. Duane Arnold 3,211 Reputation points
    2021-04-29T01:51:32.597+00:00

    Is there any alternative or better approach to it in terms of performance?

    No not really but you could use a more formulized approach by using Json or XML.

    No comments

  2. Hobbyist_programmer 621 Reputation points
    2021-04-29T16:11:14.74+00:00

    Hallo Karen,

    I have following function to serialize and deserialize to xml. It works but now i dont know how i can restore the deserialize object values back into datagridview

    SerializeObj(saved, "C:\temp\test.xml")
    
    Public Sub SerializeObj(obj As Object, ByVal path As String)
    
            Dim ws As New XmlWriterSettings With {.NewLineHandling = NewLineHandling.Entitize}
            Dim serializer As New XmlSerializer(obj.GetType, New XmlRootAttribute("Project"))
    
            Using xmlWriter As XmlWriter = XmlWriter.Create(path, ws)
                serializer.Serialize(xmlWriter, obj)
            End Using
    
        End Sub
    
        Public Function deSerializeObj(obj As Object, ByVal path As String) As Object
    
            Try
    
                Dim fs As FileStream = New FileStream(path, FileMode.Open)
                Dim serializer As New XmlSerializer(obj.GetType, New XmlRootAttribute("Project"))
                obj = CType(serializer.Deserialize(fs), Object)
                fs.Close()
                Return obj
    
            Catch ex As Exception
                Return Nothing
            End Try
    
        End Function
    

    Thanks

    No comments

  3. Karen Payne MVP 29,236 Reputation points MVP
    2021-04-29T17:28:23.183+00:00

    As mentioned in my initial reply, consider using a json file. I had time to take code I have in C# and convert to VB.

    Requires Json.net NuGet package

    Note The methods provided are generic so they will work on any class.

    92721-figure1.png

    The following image shows the class structure in a project named JsonNetLibrary where a simple console project, JsonNetLibaryConsole uses JsonNetLibrary and yes this will work also in a Windows Form project while I used a console project to be devoured of any user interface distractions.

    The following code module provides a language extension to serialize a list to a file (to use if for a single instance create another method which accepts a single instance of a class. I did a list and not a single instance as I have only so much time in my day to provide a quality response.

    Imports System.IO  
    Imports Newtonsoft.Json  
      
    Namespace LanguageExtensions  
      
        Public Module GenericExtensions  
            Private Function SettingsDefault() As JsonSerializerSettings  
                Return New JsonSerializerSettings With {.Formatting = Formatting.Indented}  
            End Function  
      
            ''' <summary>  
            ''' Write list to json file  
            ''' </summary>  
            ''' <typeparam name="TModel"></typeparam>  
            ''' <param name="list"></param>  
            ''' <param name="fileName"></param>  
            <Runtime.CompilerServices.Extension>  
            Public Sub ModeListToJson(Of TModel)(list As List(Of TModel), fileName As String)  
      
                JsonConvert.DefaultSettings = AddressOf SettingsDefault  
      
                Dim json = JsonConvert.SerializeObject(list)  
      
                File.WriteAllText(fileName, json)  
      
            End Sub  
        End Module  
    End Namespace  
    

    This class provide a deserialize process.

    Imports System.IO  
    Imports Newtonsoft.Json  
      
    Namespace Classes  
      
        Public Class Helpers  
            ''' <summary>  
            ''' Read model from json file  
            ''' </summary>  
            ''' <typeparam name="TModel"></typeparam>  
            ''' <param name="fileName"></param>  
            ''' <returns></returns>  
            Public Shared Function ReadFromJson(Of TModel)(fileName As String) As List(Of TModel)  
                Dim model As New List(Of TModel)()  
      
                If File.Exists(fileName) Then  
                    Dim json = File.ReadAllText(fileName)  
                    model = JsonConvert.DeserializeObject(Of List(Of TModel))(json)  
                End If  
                Return model  
            End Function  
        End Class  
    End Namespace  
    

    In the console project

    Public Class Person  
        Public Property FirstName() As String  
        Public Property LastName() As String  
    End Class  
    

    Mockup some data

    Public Class Mocked  
        Public Shared Function People() As List(Of Person)  
            Return New List(Of Person) From {  
                New Person() With {.FirstName = "Karen", .LastName = "Payne"},  
                New Person() With {.FirstName = "Katrina", .LastName = "Payne"}  
                }  
        End Function  
    End Class  
    

    Use it

    Imports System.IO  
    Imports JsonNetLibrary.Classes  
    Imports JsonNetLibrary.LanguageExtensions  
      
    Module Module1  
      
        Sub Main()  
            Dim fileName = "People.json"  
      
            Console.ForegroundColor = ConsoleColor.Yellow  
            Console.WriteLine("Saving list to file")  
            Console.ResetColor()  
            Mocked.People().ModeListToJson(fileName)  
      
            Console.WriteLine(New String("-"c, 40))  
      
            Dim json = File.ReadAllText(fileName)  
      
            Console.ForegroundColor = ConsoleColor.Yellow  
            Console.WriteLine("View list from file")  
            Console.ResetColor()  
            Console.WriteLine(json)  
      
            Dim results As List(Of Person) = Helpers.ReadFromJson(Of Person)(fileName)  
      
            Console.ForegroundColor = ConsoleColor.Yellow  
            Console.WriteLine("Read back file to list of person")  
            Console.ResetColor()  
            Console.WriteLine(New String("-"c, 40))  
      
            For Each person As Person In results  
                Console.WriteLine($"{vbTab}{person.FirstName} {person.LastName}")  
            Next  
            Console.ReadLine()  
        End Sub  
    End Module  
    

    92731-present.png

    ---
    92713-kpmvp.png

    No comments