Display DataGridView values in text boxes based on matching values - vb.net - vb.net

I have an SQL query that returns 2 columns of values:
country | number
NA | 1
IN | 2
CN | 3
DE | 4
And so on.
I am trying to do one of the following:
Assign these values to variables I can copy to an excel workbook
Or just use the DGV as a medium to copy values to text boxes.
For example, I have a form with country labels and textboxes next to them. I would want to click a button and have the data copied to the matching text box.
DGV number value where DGV row value = CN would be 3 and that value would be copied to the CN value text box.

If you are only using the DGV as a medium, but not actually displaying it, use a dictionary instead. Output the SQLDataReader using the SQLcommand(cmd) with the country code being the key and the number being the value. Then its as simple as:
Dim dc As Dictionary(Of String, String) = New Dictionary(Of String, String)
Dim cmd As SqlCommand = "your query string"
cmd.Connection.ConnectionString = "your con string"
Using sqlrdr As SqlDataReader = cmd.ExecuteReader()
While (sqlrdr.Read())
dc.Add(sqlrdr(0), sqlrdr(1))
End While
End Using
Then just output to the textbox:
txtNA.Text = dc.Item("NA")

If the countries are fixed as your question refers, then you could use something like this:
First, use the names of the countries to name the TextBoxes (txtNA, txtIN, txtCN,...)
Then you can put this code:
Try
For i = 0 To DataGridView1.RowCount - 1
Me.Controls("txt" & DataGridView1.Rows(i).Cells(0).Value.ToString).Text = _
DataGridView1.Rows(i).Cells(1).Value.ToString()
Next
Catch
End Try

The following will not work 'as is' if using classes via dragging tables from the data source window in the ide. We would need to cast objects not to a DataTable but to the class definition in a TableAdapter, DataSet and BindingSource.
Here is a method which reads from SQL-Server database table, places data into a DataTable, data table become the data source for a BindingSource which becomes the data source for the DataGridView. Using a BindingSource we now use the BindingSource to access row data rather than the DataGridView and it's always best to go to the data source rather than the user interface.
BindingSource.Current is a DataRowView, drill down to Row property then field language extension method to get strongly typed data for the current row if there is a current row as you will note I am using two forms of assertions, first, do we have a data source and is the data source populated then we see if there is indeed a current row.
From here we can set variable, properties or control text to the field values of the current row.
Note in form load I seek a specific country (totally optional) and then if found go to that row.
Least but not last, I like using xml literals when doing SQL in code so there is no string concatenation and we can format the statement nicely.
Public Class Form1
''' <summary>
''' Permits obtaining row data in DataGridView
''' </summary>
''' <remarks></remarks>
Dim bsCountries As New BindingSource
Public Property Country As String
Public Property CountryNumber As Integer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As New DataTable
Using cn As New SqlClient.SqlConnection With
{
.ConnectionString = My.Settings.KarenDevConnectionString
}
Using cmd As New SqlClient.SqlCommand With {.Connection = cn}
' xml literal to make command text
cmd.CommandText =
<SQL>
SELECT [ID],[Country],[Number]
FROM [Countries]
</SQL>.Value
cn.Open()
dt.Load(cmd.ExecuteReader)
dt.Columns("ID").ColumnMapping = MappingType.Hidden
bsCountries.DataSource = dt
DataGridView1.DataSource = bsCountries
' let's try and move to a country
Dim index As Integer = bsCountries.Find("Country", "CN")
If index > -1 Then
bsCountries.Position = index
End If
End Using
End Using
End Sub
''' <summary>
''' Put field values into TextBoxes
''' </summary>
''' <remarks></remarks>
Private Sub DoWork()
If bsCountries.DataSource IsNot Nothing Then
If bsCountries.Current IsNot Nothing Then
Dim row As DataRow = CType(bsCountries.Current, DataRowView).Row
TextBox1.Text = row.Field(Of String)("Country")
TextBox2.Text = row.Field(Of Integer)("Number").ToString
' we can also do this
Me.Country = row.Field(Of String)("Country")
Me.CountryNumber = row.Field(Of Integer)("Number")
End If
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
DoWork()
End Sub
End Class

Related

How would you structure data with different datatypes in VB.NET

Right now I have many locations with this structure. At the moment I have: name as string and x,y,z positions as single. So it's a mix of data types and I might want to add both more data in the future and also other data types. I must be able to easily extract any part of this data.
Example of how I'll work with this data is: When I choose South Wales from a combobox then I want to get its properties, x,y,z populated in a textbox. So they need to be "linked". If I choose London then it'll have its x,y,z properties etc.
My initial idea is just to dim every single data such as in the first example below. This should be the easiest way with 100% control of what's what, and I could easily extract any single data but at the same time might get tedious I assume, or am I wrong? Is it a good way to approach this?
Dim SW_FP As String = "South Wales"
Dim SW_FP_X As Single = "489,1154"
Dim SW_FP_Y As Single = "-8836,795"
Dim SW_FP_Z As Single = "109,6124"
The next example below is something i just googled up. Is this a good method?
Dim dt As DataTable = New DataTable
dt.Columns.Add("South Wales", GetType(String))
dt.Columns.Add("489,1154", GetType(Single))
dt.Columns.Add("-8836,795", GetType(Single))
dt.Columns.Add("109,6124", GetType(Single))
OR should I use something else? Arrays, Objects with properties... and this is where my ideas end. Are there other methods? XML?
I want to do it in a smart way from start instead of risking to rewrite/recreate everything in the future. So my main question is: Which method would you suggest to be the smartest to choose? and also if you could provide a super tiny code example.
You mentioned that when you choose an item you want to get it's properties. This shows that you are looking for objects. If not using a database one example could be to make Location objects and have a List of these to be added or removed from. Then you have a lot of different ways to get the data back from the List. For example:
Class:
Public Class Location
Public Property Name As String
Public Property X As Single
Public Property Y As Single
Public Property Z As Single
End Class
List:
Dim locations As New List(Of Location)
Dim location As New Location With {
.Name = "South Wales",
.X = 1.1,
.Y = 1.2,
.Z = 1.3
}
locations.Add(location)
LINQ to get result:
Dim result = locations.SingleOrDefault(Function(i) i.Name = "South Wales")
This is just an example for use within your program, hope it helps.
Disclaimer: Untested code. It's more to guide you than copy-paste into your project.
First, create a Class that will represent the structured data:
Public Class Location
Public Property Name As String
Public Property PositionX As Single
Public Property PositionY As Single
Public Property PositionZ As Single
Public Sub New()
Me.New (String.Empty, 0, 0, 0)
End Sub
Public Sub New(name As String, x As Single, y As Single, z As Single)
Me.Name = name
Me.PositionX = x
Me.PositionY = y
Me.PositionZ = z
End Sub
Now, you can create a List(Of Location) and use that List to bind to a ComboBox, like this:
Dim list As New List(Of Location) = someOtherClass.ReadLocations ' Returns a List(Of Location) from your database, or file, or whatever.
cboLocations.DataSource = list
cboLocations.DisplayMember = "Name" ' The name of the Location class' Property to display.
cboLocations.ValueMember = "Name" ' Use the same Name Property since you have no ID.
You can also forego the list variable declaration like the following, but I wanted to show the declaration of list above:
cboLocations.DataSource = someOtherClass.ReadLocations
Function someOtherClass.ReadLocations() may populate the List(Of Locations) in a way similar to this. Note I'm not including data access code; this is just an example to show how to add Location objects to the List(Of Location):
Dim list As List(Of Location)
' Some loop construct
For each foo in Bar
Dim item As New Location(foo.Name, foo.X, foo.Y, foo.Z)
list.Add(item)
' End loop
Return list
The "magic" happens when you select an option from the ComboBox. I forget the ComboBox event offhand, so that's homework for you :-) You take the selected Object of the ComboBox and cast it back to the native type, in this case Location:
Dim item As Location = DirectCast(cboLocations.SelectedItem, Location)
txtName.Text = item.Name
txtPosX.Text = item.PositionX.ToString
txtPosY.Text = item.PositionY.ToString
txtPosZ.Text = item.PositionZ.ToString
Here is one way, using a DataTable as you mentioned. This is a stand alone example project just to show code used.
This example loads data from file is found and saves data on exit.
Form1 Image
' Stand alone example
' needs DataGridView1, Label1 and
' ComboBox1 on the Designer
' copy/replace this code with default
Option Strict On
Option Explicit On
Public Class Form1
Dim dt As New DataTable("Freddy")
Dim bs As New BindingSource
'edit path/filename to use as test data path
Dim filepath As String = "C:\Users\lesha\Desktop\TestData.xml"
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
dt.WriteXml(filepath)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
With dt
dt.Columns.Add("Country", GetType(String))
dt.Columns.Add("x", GetType(String))
dt.Columns.Add("y", GetType(String))
dt.Columns.Add("z", GetType(String))
' add extra column to hold concatenated
' location (could be a hidden column)
dt.Columns.Add("CombLoc", GetType(String), "'x = ' + x + ' y = ' + y + ' z = ' + z")
If IO.File.Exists(filepath) Then
' saved file found so load it
dt.ReadXml(filepath)
Else
' no saved file so make one test row
.Rows.Add("South Wales", 489.1154, -8836.795, 109.6124)
End If
End With
bs.DataSource = dt
DataGridView1.DataSource = bs
' set any properties for DataGridView1
With DataGridView1
' to hide Combined Location column
.Columns("CombLoc").Visible = False
' dontwant row headers
.RowHeadersVisible = False
End With
set up ComboBox
With ComboBox1
.DataSource = bs
' displayed item
.DisplayMember = "Country"
' returned item
.ValueMember = "CombLoc"
If .Items.Count > 0 Then .SelectedIndex = 0
End With
' default Label text
Label1.Text = "No items found"
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
no items in list so exit sub
If ComboBox1.SelectedIndex < 0 Then Exit Sub
send returneditem to Label
Label1.Text = ComboBox1.SelectedValue.ToString
End Sub
End Class

Datatables Not Merging VB.NET

I have some code that is intended to:
1. Loop through a datagrid that is user populated
2. Search an access database using the input criteria
3. Return the results as a datatable
4. Merge additional results to that datatable
5. Bind the merged table results to a DataGridView
The query works, results return as expected with a single value search. The query will also return one of the two test values if I use the user input DataGridView. However, it will not combine the two results before outputting to the results_DataGridView. I have also tried using .Fill from the adapter to add onto my temp table and use that as the datasource.
Option Strict On
Dim dt_TempTable As New DataTable
Dim dt_ContentsTable As New DataTable
Dim SerialNumbers As New List(Of String)
Dim PanelIDs As New List(Of String)
Dim MultiSearch As Boolean
Private Sub bgwk_data_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgwk_data.DoWork
If Not (MultiSearch) Then
Retrieveinfo(Me.txt_SerialNumber.Text, Me.txt_PanelID.Text) 'Local
Else
Dim arrSN As String() = SerialNumbers.ToArray()
Dim arrPID As String() = PanelIDs.ToArray()
For i = 0 To arrSN.Count - 1
If i > 0 Then
Retrieveinfo(arrSN(i), arrPID(i)) 'Local - Run query and create a new temp table of results
dt_ContentsTable.Merge(dt_TempTable) 'Merge new temp table to current contents table
Else
dt_ContentsTable = Retrieveinfo(arrSN(i), arrPID(i)) 'Return the original temp table to the contents table (datagridview datasource)
End If
Next
End If
End Sub
'Gets the Data by SerialNumber and saves it to dt_TempTable to be bound afterwards
Private Function Retrieveinfo(SerialNumber As String, PanelID As String) As DataTable
Dim ds As New datasource
Dim tblAdapt As New datasourceTableAdapters.toHTML_SPC_DataTableAdapter
tblAdapt.GetData(dt_TempTable, SerialNumber, PanelID)
Return dt_TempTable 'Return the table
End Function
'Updates dg_data with the datatable from Retrieveinfo and refreshes the form
Private Sub bgwk_dataRunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgwk_data.RunWorkerCompleted
'Unlocks ability to search new things
Me.txt_PanelID.ReadOnly = False
Me.txt_SerialNumber.ReadOnly = False
Me.dg_data.ReadOnly = False
'Binds the backgroundworker results to the datagridview
Me.dg_data.DataSource = Nothing
Me.dg_data.DataSource = dt_ContentsTable
Me.dg_data.Refresh()
Me.Refresh()
End Sub
I understand that merge can be used on DataTables, but perhaps this is incorrect usage?
I'd go with a condition in the multi-search loop:
If dt_ContentsTable.Rows.Count = 0 Then
dt_ContentsTable = dt_TempTable.Clone()
End If
dt_ContentsTable.Merge(dt_TempTable)
This way, the first time, its at least creating the columns of the dt_ContentsTable.
I also don't see any code in the single search where dt_ContentsTable is assigned. So, in the single search, I recommend you assign dt_ContentsTable to dt_TempTable.

Filling ComboBox Column in DatagridView VB.Net

i have a datagridview with 2 columns as combobox and i want to fill the second one depending on the first one.
Ex. I have a table in my database with stations
TableStations
Station 1
Station 2
And each stations has a different amount of outputs
Ex.
Station 1 Station 2
OutP1 OutP5
OutP2 OutP6
OutP7
What i want to do in the datagridview is that when the user selects from the first combobox a station the next combobox gets filled with the outputs for that station, my problem comes when the user adds a second row in the datagridview if he selects a diferent station the info in the first row will be modified.
Is there any solution for this or any other way to do what i want?
Thanks in advance
EDIT: this is the code im using
Con.Open()
cmd.Parameters.Clear()
With cmd
.CommandText = "Select output From List_outputs where station=#station"
.Parameters.AddWithValue("#station", datagridview1.Item(0, e.RowIndex).Value)
.Connection = Con
reader = .ExecuteReader
End With
combobox2.Items.Clear()
While reader.Read
combobox2.Items.Add(reader("output "))
End While
reader.Close()
This code is under the cellclick event of my datagridview.
This is a bit tricky since you can't set the column's data source. Setting the column's data source affects the entire column. You must set the data source of each cell separately. I'll show you how to do it.
First add a DataGridView in an empty form. Don't add the columns, we're going to add the columns by code. You don't have to add the columns by code in your real project, but please follow what I did in this example. I add comments to make the code easy to understand. I choose to create two classes to hold Station and Output. This is also optional, you can just use a DataReader and add them manually. Hope this helps you.
Public Class Form1
Dim outputs As List(Of Output) ' this holds the fake output data.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Replace this section with the code to retrieve stations from database.
Dim stations As New List(Of Station) From {
New Station() With {.StationName = "Station 1"},
New Station() With {.StationName = "Station 2"}
}
' Add stations to first combobox
Dim firstColumn = New DataGridViewComboBoxColumn()
For Each station In stations
firstColumn.Items.Add(station.StationName)
Next
' Populate fake data, replace this section with the code to retrive outputs from database.
outputs = New List(Of Output) From {
New Output() With {.OutputName = "OutP1", .StationName = "Station 1"},
New Output() With {.OutputName = "OutP2", .StationName = "Station 1"},
New Output() With {.OutputName = "OutP5", .StationName = "Station 2"},
New Output() With {.OutputName = "OutP6", .StationName = "Station 2"},
New Output() With {.OutputName = "OutP7", .StationName = "Station 2"}
}
' add combobox columns to datagridview
DataGridView1.Columns.Add(firstColumn)
DataGridView1.Columns.Add(New DataGridViewComboBoxColumn())
End Sub
Private Sub DataGridView1_CellBeginEdit(sender As Object, e As DataGridViewCellCancelEventArgs) Handles DataGridView1.CellBeginEdit
' Only process if the column is the second combobox.
' You will need to change the index according to your second combobox index.
' e.ColumnIndex = 1 because the second combobox index is 1 in this sample.
If e.ColumnIndex = 1 Then
' Filter the outputs by selected Station in the row.
' Change the ColumnIndex to your first combobox index.
' DataGridView1(0, e.RowIndex) because the first combobox index is 0 in this sample.
Dim outputByStation = outputs.Where(Function(x) x.StationName = DataGridView1(0, e.RowIndex).Value.ToString())
' Get current cell, we're going to populate the combobox
Dim currentCell = CType(DataGridView1(e.ColumnIndex, e.RowIndex), DataGridViewComboBoxCell)
' Populate the cell's combobox.
currentCell.Items.Clear()
For Each output In outputByStation
currentCell.Items.Add(output.OutputName)
Next
End If
End Sub
End Class
Public Class Station
Public Property StationName As String
End Class
Public Class Output
Public Property OutputName() As String
Public Property StationName() As String
End Class
Screenshot:

Database Lookup From ComboBox selection

I have a question about database values and how to determine the id of a value that has been changed by the user at some point.
As it is currently set up there is a combobox that is populated from a dataset, and subsequent text boxes whose text should be determined by the value chosen from that combobox.
So let's say for example you select 'Company A' from the combobox, I would like all the corresponding information from that company's row in the dataset to fill the textboxes (Name = Company A, Address = 123 ABC St., etc.,)
I am able to populate the combobox just fine. It is only however when I change the index of the combobox that this specific error occurs:
An unhandled exception of type 'System.Data.OleDb.OleDbException'
occurred in System.Data.dll
Additional information: Data type mismatch in criteria expression.
Here is the corresponding code:
Imports System.Data.OleDb
Public Class CustomerContact
Dim cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|datadirectory|\CentralDatabase.accdb;")
Dim da As New OleDbDataAdapter()
Dim dt As New DataTable()
Private Sub CustomerContact_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cn.Open()
da.SelectCommand = New OleDbCommand("select * from Customers", cn)
da.Fill(dt)
Dim r As DataRow
For Each r In dt.Rows
cboVendorName.Items.Add(r("Name").ToString)
cboVendorName.ValueMember = "ID"
Next
cn.Close()
End Sub
Private Sub cboVendorName_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboVendorName.SelectedIndexChanged
cn.Open()
da.SelectCommand = New OleDbCommand("select * from Customers WHERE id='" & cboVendorName.SelectedValue & "'", cn)
da.Fill(dt)
Dim r As DataRow
For Each r In dt.Rows
txtNewName.Text = "Name"
txtAddress.Text = "Address"
Next
cn.Close()
End Sub
The error is caught at Line 24 of this code, at the second da.Fill(dt) . Now obviously from the exception I know that I am sending in a wrong datatype into the OleDbCommand, unfortunately I am a novice when it comes to SQL commands such as this. Also please keep in mind that I can't even test the second For loop, the one that is supposed to fill the Customer information into textboxes (for convenience I only copied the first two textboxes, of which there are nine in total). I am think I could use an If statement to determine if the row has been read, and from there populate the textboxes, but I will jump that hurdle when I can reach it.
Any guidance or suggestions would be much appreciated. Again I am a novice at managing a database and the code in question pertains to the project my current internship is having me write for them.
Since you already have all the data from that table in a DataTable, you dont need to run a query at all. Setup in form load (if you must):
' form level object:
Private ignore As Boolean
Private dtCust As New DataTable
...
Dim SQL As String = "SELECT Id, Name, Address, City FROM Customer"
Using dbcon = GetACEConnection()
Using cmd As New OleDbCommand(SQL, dbcon)
dbcon.Open()
dtCust.Load(cmd.ExecuteReader)
End Using
End Using
' pk required for Rows.Find
ignore = True
dtCust.PrimaryKey = New DataColumn() {dtCust.Columns(0)}
cboCust.DataSource = dtCust
cboCust.DisplayMember = "Name"
cboCust.ValueMember = "Id"
ignore = False
The ignore flag will allow you to ignore the first change that fires as a result of the DataSource being set. This will fire before the Display and Value members are set.
Preliminary issues/changes:
Connections are meant to be created, used and disposed of. This is slightly less true of Access, but still a good practice. Rather than connection strings everywhere, the GetACEConnection method creates them for me. The code is in this answer.
In the interest of economy, rather than a DataAdapter just to fill the table, I used a reader
The Using statements create and dispose of the Command object as well. Generally, if an object has a Dispose method, put it in a Using block.
I spelled out the columns for the SQL. If you don't need all the columns, dont ask for them all. Specifying them also allows me to control the order (display order in a DGV, reference columns by index - dr(1) = ... - among other things).
The important thing is that rather than adding items to the cbo, I used that DataTable as the DataSource for the combo. ValueMember doesn't do anything without a DataSource - which is the core problem you had. There was no DataSource, so SelectedValue was always Nothing in the event.
Then in SelectedValueChanged event:
Private Sub cboCust_SelectedValueChanged(sender As Object,
e As EventArgs) Handles cboCust.SelectedValueChanged
' ignore changes during form load:
If ignore Then Exit Sub
Dim custId = Convert.ToInt32(cboCust.SelectedValue)
Dim dr = dtCust.Rows.Find(custId)
Console.WriteLine(dr("Id"))
Console.WriteLine(dr("Name"))
Console.WriteLine(dr("Address"))
End Sub
Using the selected value, I find the related row in the DataTable. Find returns that DataRow (or Nothing) so I can access all the other information. Result:
4
Gautier
sdfsdfsdf
Another alternative would be:
Dim rows = dtCust.Select(String.Format("Id={0}", custId))
This would return an array of DataRow matching the criteria. The String.Format is useful when the target column is text. This method would not require the PK definition above:
Dim rows = dtCust.Select(String.Format("Name='{0}'", searchText))
For more information see:
Using Statement
Connection Pooling
GetConnection() method aka GetACEConnection

How to sort DataGridView Column by date in VB visual studio 2012?

In my DGV, I have date list in the column (1):
11-Sep-2014
11-May-2011
11-Jan-2014
11-Mar-2014
12-Sep-2010
how to get descending result like this:
11-Sep-2014
11-Mar-2014
11-Jan-2014
11-May-2011
12-Sep-2010
The Column(1) is not DateTime type but SortText type, I must set string like that. Could it sorted?
I have tried using code:
DGV.Columns(1).SortMode = DGV.Sort(DGV.Columns(1), System.ComponentModel.ListSortDirection.Descending)
but it's useless, it don't sort by date :(
this is my DGV:
Okeh, this is my DGV code in brief:
Imports System.Data.OleDb
Public Class LapTransaksiSimpanan
Public Sub Koneksi()
str = "provider=microsoft.jet.oledb.4.0;data source=dbkoperasi.mdb"
Conn = New OleDbConnection(str)
If Conn.State = ConnectionState.Closed Then
Conn.Open()
End If
End Sub
Sub TampilGrid()
da = New OleDbDataAdapter("select * from LapTransaksiSimpanan", Conn)
ds = New DataSet
da.Fill(ds, "LapTransaksiSimpanan")
DGV.DataSource = ds.Tables("LapTransaksiSimpanan")
'on the below I wanna to sort the column, my code below is useless :(
DGV.Sort(DGV.Columns(1), System.ComponentModel.ListSortDirection.Descending)
DGV.Columns("ID_Simpanan").Width = 120
DGV.Columns("NAK").Width = 37
DGV.Columns("Tanggal").Width = 75
DGV.Columns("Jumlah").Width = 110
End Sub
Private Sub Setoran_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call Koneksi()
Call TampilGrid()
End Sub
End Class
There's a difference between storing and displaying data.
You need to change you database table schema. The Tanggal column should be of type date or datetime. When you've fixed this, it's trivial to display dates using a custom format:
Me.DGV.Columns("Tanggal").DefaultCellStyle.Format = "dd-MMM-yyyy"
If you for some reason cannot change the schema, then you need to create a custom comparer by implementing IComparer. There's an example at the bottom of this MSDN page.
Dim tnd As Date
For Me.i = 0 To X1.RowCount - 2
tnd = X1.Item(1, i).Value
X1.Item(6, i).Value = tnd.ToOADate.ToString
Next
X1 is DataGridView
Column 1 would have your date ex 5/4/1987
Column 6 would be calculated as MS date number in integer and must be converted to string.
Make sure X1 grid is Sort enabled
Now simply click on Column 6 header to sort.
Hope that works.