DataTable Column.Expression Throw Error - vb.net

I Have Data Table which Contains Few row like below
CH1 CH2 Ch3 CH4 CH5
1 2 1 2 3
3 3 1 2 3
3 3 1 1 2
1 3 3 3 3
1 2 3 3 0
3 3 1 2 0
3 3 1 1 2
then I Try to add new column like
Dim col As New DataColumn("VCH1", GetType(Decimal),"(CH1+CH2+ch3)/CH5")
DtReadings.Columns.Add(col)
at that time give me error : Attempted to divide by zero. Because of CH5 have zero values,
but I need to add Dynamic Column with different Expression at run time ,how to avoid such type of error any Idea please Help.
Expression value not fixed,User Create expression for dynamic Column.
not only handle divide by zero error ,to handle all type of computing error

You can catch the DivideByZeroException and then assign the value you want:
Try
col = New DataColumn("VCH1", GetType(Decimal), "(CH1+CH2+ch3)/CH5")
Catch ex As DivideByZeroException
col = New DataColumn("VCH1", GetType(Decimal), "0")
End Try
DtReadings.Columns.Add(col)

The Expression syntax allow the use of the IIF statement
You could build your DataColumn using this kind of syntax for the Expression
col = New DataColumn("VCH1", GetType(Decimal), "IIF(CH5 = 0, 0, (CH1+CH2+ch3)/CH5)")
Of course, being the Expression a string property you could build your expression dynamically based on the particular requirement you have at the moment. With IIF or ISNULL you could build your string on the fly before adding the column. Something like this pseudocode
Dim currentExpression as String = BuildCurrentExpression()
col = New DataColumn("VCH1", GetType(Decimal), currentExpression)

Simply Create One Extension for Solve my Problem,that's take a time but i have no problem
<Extension()>
Public Function ToCompute(value As DataTable, exp As String, inputColumn As String) As DataTable
Dim tempdt As New DataTable
tempdt = value.Clone
tempdt.Columns(inputColumn).Expression = exp
For Each row As DataRow In value.Rows.Cast(Of DataRow).ToList
Try
tempdt.Rows.Add(row.ItemArray)
value.Rows(value.Rows.IndexOf(row))(inputColumn) = tempdt.Rows(0)(inputColumn).ToString
tempdt.Rows.Clear()
Catch ex As Exception
tempdt.Rows.Clear()
value.Rows(value.Rows.IndexOf(row))(inputColumn) = 0
Continue For
End Try
Next
Return value
End Function

Related

linq filter columns rather than data

Firstly, I'm not sure if what I'm asking is possible or not so apologies if I'm asking a stupid question.
So I am able to filter a DataTable using linq to get the data I need, I'm wondering if it's possible to filter the columns using a simlar statement.
For example if I have the below datatable dtMyData
ID
Name
1
2
3
4
1
Conor
100
87
3
0
2
Frank
35
70
0
0
3
Jeff
35
13
0
57
I can filter it to the below using the following statement
dtMyData = dtMyData.AsEnumerable().Where(Function (f) f("Name").ToString().Equals("Frank")).CopyToDataTable
ID
Name
1
2
3
4
2
Frank
35
70
0
0
What I'm wanting to do (If it's possible) is filter the columns in a similar way so that I can select all of the columsn > 2 plus the first 2 columns. Giving me the following columns
ID
Name
3
4
1
Conor
3
0
2
Frank
0
0
3
Jeff
0
57
Take a look at this method:
Private Function CopyTable(source As DataTable, columnsToKeep As IEnumerable(Of String)) As DataTable
Dim copiedTable As DataTable = source.Clone()
Dim columnsToRemove() As DataColumn = copiedTable.Columns.Cast(Of DataColumn).Where(Function(column) Not columnsToKeep.Contains(column.ColumnName)).ToArray()
For i As Integer = 0 To columnsToRemove.Length - 1
copiedTable.Columns.Remove(columnsToRemove(i))
Next
For Each row As DataRow In source.Rows
Dim values As New List(Of Object)
For Each column As DataColumn In copiedTable.Columns
values.Add(row.Item(column.ColumnName))
Next
copiedTable.Rows.Add(values.ToArray())
Next
Return copiedTable
End Function
What this does is
Clone the DataTable
Loop over the copied DataTable and remove the columns that are not in the columnsToKeep
Loop over the original DataTable and add the rows to the copied DataTable without the cells that are not in the columnsToKeep
Fiddle: https://dotnetfiddle.net/2l6wk9
Edit
It would actually be easier to use DataTable.Copy over DataTable.Clone, my apologies:
Private Function CopyTable(source As DataTable, columnsToKeep As IEnumerable(Of String)) As DataTable
Dim copiedTable As DataTable = source.Copy()
Dim columnsToRemove() As DataColumn = copiedTable.Columns.Cast(Of DataColumn).Where(Function(column) Not columnsToKeep.Contains(column.ColumnName)).ToArray()
For i As Integer = 0 To columnsToRemove.Length - 1
copiedTable.Columns.Remove(columnsToRemove(i))
Next
Return copiedTable
End Function
What this updated code does is:
Copy the DataTable with its data
Loop over the copied DataTable and remove the columns that are not in the columnsToKeep
Fiddle: https://dotnetfiddle.net/NEIm2t

read datable and store value in array

Name | CategorieID | FullCategorie_ID
---- ------------- ----------------
A 1 12
B 1 13
C 5 14
D 3 15
E 6 16
I want to read data from datatable and store a complete row in array and then return it
I cannot get the point to save a DataTable (that has rows and columns) inside an Array (that has only rows) but this is your question, not mine!
So, the code you are looking for is something like this:
Dim dt As New System.Data.DataTable
Dim arrayString(dt.Rows.Count - 1) As String
For dr As Integer = 0 To dt.Rows.Count
For dc As Integer = 0 To dt.Columns.Count
arrayString(dr) = arrayString(dr) & "$" & dt.Rows(dr).Item(dc)
'I added a special char ($) to easily split up data later
Next
Next
If you want to split up in columns your data, just use String.Split like shown below:
Dim first_array_row () as String = arrayString.Split("$")
But I higly suggest you to review your code/idea, It's better for you to find another way, because this workaround is horrible.
Instead why not use a List Class and a Dictionary Class
something like:
Dim values As New List(Of Dictionary(Of String, String))()

Greater Than and Less Than in Column in Datagridview VB.Net

I have 3 columns in datagridview lets call it column 0,1 and 2 and here what it looks like.
My question is how can I make the column 0 turn to color orange when column 2 is greater than column 1? For example the Banana Catsup 4 kg column 2 has a 5 and column 1 is greater than column 2 so in that case the column 0 will not turn to orange but in my example it turns to orange. Here is my code
Try
For i As Integer = DataGridView1.RowCount - 1 To 3 Step -1
If DataGridView1.Rows(i).Cells(1).Value > DataGridView1.Rows(i).Cells(2).Value Then
Me.DataGridView1.Rows(i).Cells(1).Style.BackColor = Color.Orange
End If
Next
Catch
End Try
When i observe my code it seems that my code works only on the first number. Please help me
TYSM
Why complicate things when you can just do it like this?
Try
For i = 0 To DataGridView1.RowCount - 1
If Val(DataGridView1.Rows(i).Cells(1).Value.ToString) > Val(DataGridView1.Rows(i).Cells(2).Value.ToString) Then
Me.DataGridView1.Rows(i).Cells(0).Style.BackColor = Color.Orange
End If
Next
Catch ex As Exception
MsgBox(ex.Message)
End Try
Also, having an empty catch will give you trouble sooner or later.
Added Val() to cells to make sure it won't cause any problem when it's blank.
You are comparing two string values. You first need to convert col1 and col2 values to INT then compare.
Try
For i As Integer = DataGridView1.RowCount - 1 To 3 Step -1
If CInt(Replace(DataGridView1.Rows(i).Cells(1).Value,",","")) > CInt(Replace(DataGridView1.Rows(i).Cells(2).Value,",","")) Then
Me.DataGridView1.Rows(i).Cells(1).Style.BackColor = Color.Orange
End If
Next
Catch
End Try

Find and sum value of a datagridview column in vb.net

I want to find and sum qty value of searched id in data grid view column am using this code
Dim tqty As Double
For Each row As DataGridViewRow In dgv.Rows
If row.Cells.Item(0).Value = cmbItemCode.Text Then
tqty += row.Cells.Item(4).Value
Textbox1.text=tqty
Exit For
End If
Next
The problem is that Textbox1 shows only one top searched row value. For example
id item name qty
1 abc 4
2 xyz 10
1 abc 10
Textbox1 shows the Result only 4.
As soon as you hit the first value, you exit the for statement. Therefore you never get pass the first value. Erase the Exit For it should work.
If DataGridView2.RowCount > 1 Then
Dim tqty As Integer = 0
'if you have the other column to get the result you could add a new one like these above
For index As Integer = 0 To DataGridView2.RowCount - 1
amount += Convert.ToInt32(DataGridView2.Rows(index).Cells(2).Value)
'if you have the other column to get the result you could add a new one like these above (just change Cells(2) to the one you added)
Next
TextBox1.Text = tqty

Unable to select values in second column listview

I've a listview that dynamically populates values between two columns in this fashion:
column 1 | column 2
value1 | value 2
value3 | value 4
however I'm unable to select any values in column 2 - is there a property of the listview that's preventing me from doing this or is it the way I populate these columns? Here's my code to populate the column:
For k = 0 To UBound(tempValues)
Dim itm As New ListViewItem(tempValues(k))
If k Mod 2 = 0 Then
listview1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
itm.SubItems.Add(tempValues(k + 1))
listview1.Items.Add(itm)
End If
listview1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
Next
Any ideas?
The closest I can see for this is to set listView1.FullRowSelect = true (I assume you have listView1.View = View.Details?)
This however will only give you full row selecting - Remember the 2nd column represents the 1st Sub Item of the listview's items.
If you want multiple columns of data, you might be better off setting listView1.View = View.Details = View.List, which will cause it to wrap a single list of items onto multiple columns when it runs out of vertical space.
Edit:
If you use listView1.View = View.List, your population would need to change to the following:
For k = 0 To UBound(tempValues)
listview1.Items.Add(new ListViewItem(tempValues(k))
Next
listview1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
But it would mean you end up with the list like so:
Value 1
Value 2
Value 3
Value 4
And if ListView was made too short to display, all these, it would wrap them:
Value 1 Value 4
Value 2
Value 3