How to fill all textboxes after click on gridview by making classLibrary? - asp.net

I want to make a class library containing classes for common tasks.
I made such a class that worked very well on some forms but it have some errors that I can't trace down.
This is my code and it does the following:
It accepts 3 parameters: form name, datagridview name and the textbox name prefixes.
It counts the datagrid columns
It takes the current row index
It makes the array with a length corresponding to the number of columns
It's looking in the form for all text boxes that have a name with prefix parameter + column name and set the value in it
Code:
Sub setRecordFieldToControl(ByVal root As Form, ByVal dgv As DataGridView, ByVal cntrlPreNam1 As String, ByVal cntrlPreNam2 As String)
Dim j, k, z As Integer
Dim s As String
z = dgv.ColumnCount
k = dgv.CurrentRow.Index
j = 0
Dim headTxt(z) As String
For indx = 0 To z - 1
headTxt(indx) = dgv.Columns(indx).HeaderText
Next
For Each i As Control In root.Controls
If TypeOf i Is MaskedTextBox Or TypeOf i Is ComboBox Then
For clm = 0 To z
If i.Name = cntrlPreNam1 & headTxt(clm) Or i.Name = cntrlPreNam1 & headTxt(clm) Then
s = (dgv.Rows(k).Cells(j).Value)
i.Text = s
' i.Text = dgv.Item(j, k).Value
j = j + 1
If j >= z Then
Exit For
End If
End If
Next
End If
Next
End Sub
My problem is: on some forms I got this error:
Index is out of range for line i.Text = s
The error does not show up when I put something else in my text box, the error only appears when I put the s in it.

The error is probably in the line
For clm = 0 To z
It should read
For clm = 0 To z - 1
The column indexes range from 0 .. number_of_columns - 1.
UPDATE
There are several problems with your code:
The logic seems wrong to me. You are looking for the column (clm) with the right name but then take the value of another column (j). Why?
The variable names are not speaking and are even misleading (e.g. i for a Control).
You have nested loops with an O(n^2) behavior. See Big O Notation.
I suggest rewriting it. Use a dictionary for the possible control names, that stores the corresponding column indexes by name. Dictionaries have a nearly constant access speed. In other words: Lookups are very fast.
Sub SetRecordFieldToControl(ByVal root As Form, ByVal dgv As DataGridView, _
ByVal cntrlPrefix1 As String, ByVal cntrlPrefix2 As String)
Dim currentRowIndex As Integer = dgv.CurrentRow.Index
Dim columnDict = New Dictionary(Of String, Integer)
For i As Integer = 0 To dgv.ColumnCount - 1
Dim headerText As String = dgv.Columns(i).HeaderText
columnDict.Add(cntrlPrefix1 & headerText, i)
columnDict.Add(cntrlPrefix2 & headerText, i)
Next
For Each cntrl As Control In root.Controls
If TypeOf cntrl Is MaskedTextBox Or TypeOf cntrl Is ComboBox Then
Dim columnIndex As Integer
If columnDict.TryGetValue(cntrl.Name, columnIndex) Then
Dim value As Object
value = dgv.Rows(currentRowIndex).Cells(columnIndex).Value
If Not value Is Nothing Then
cntrl.Text = value.ToString()
End If
End If
End If
Next
End Sub

Related

How to separate group of line series in different panes in DevExpress BootstrapChart?

Right now, I'm developing web application using DevExpress BootstrapChart (v17.2.13.0) and I have binded the control with object datasource. Here is the example data used to be displayed in the graph:
Here is my objectives:
The graph will show the values of "ademand_im" and "rdemand_im" in different panes (I named them pane "A" and "B")
Each pane has "data_time" (date and time) as X-axis and the values ("ademand_im" or "rdemand_im") as Y-axis
Also, the values in each pane will be grouped by "hardware_id" so, in this case, there should be 2 line series of "83245551" and "88310991" in each pane (Note that "hardware_id" can be varied from time to time).
So the graph should look like this:
However, what I only acheive at this moment is that either the line series are shown in both panes but not grouped or not show anything in the graph.
Here is my code:
<dx:BootstrapChart ID="chart" ClientInstanceName="chart" runat="server"
DataSourceID="ods_ChartData" Height="640px" TitleText="Chart Data" CrosshairEnabled="true" Panes="A,B">
<ClientSideEvents Init="OnChartInit" />
<SettingsToolTip Shared="true" Enabled="true" OnClientCustomizeTooltip="ChartToolTip" />
<ArgumentAxis ArgumentType="System.DateTime" GridVisible="True" MinorGridVisible="True"
TickVisible="True" MinorTickVisible="True" TickInterval="1" MinorTickCount="3" TitleText="Date">
<Label DisplayMode="Rotate" RotationAngle="-0" Format-Formatter="FormatDate" />
</ArgumentAxis>
<ValueAxisCollection>
<dx:BootstrapChartValueAxis Pane="A" TitleText="ademand_im" />
<dx:BootstrapChartValueAxis Pane="B" TitleText="rdemand_im" />
</ValueAxisCollection>
<SettingsCommonSeries Type="Line" ArgumentField="data_time" Point-Size="0" />
<SettingsSeriesTemplate NameField="hardware_id" />
<SeriesCollection>
<dx:BootstrapChartLineSeries Pane="A" ValueField="ademand_im" />
<dx:BootstrapChartLineSeries Pane="B" ValueField="rdemand_im" />
</SeriesCollection>
</dx:BootstrapChart>
In this code, if I remove the "SettingsSeriesTemplate" line, the data will show in both panes but only in single line in each pane. However, if I keep this line the graph will not show anything.
After I tried to understand how this control works, the only solution I found is that I have to pivot "hardware_id" columns into "ademand_im" and "rdemand_im" values, which may be not the ideal one.
So instead of having "hardware_id", "ademand_im" and "rdemand_im" columns, the table should be transformed to have like "ademand_im_83245551", "ademand_im_88310991", "rdemand_im_83245551" and "rdemand_im_88310991" columns instead.
This is how the table after transforming looks like:
Here is the function codes that I used to transform the table (VB.NET):
<Extension()>
Public Function PivotDataTableColumnGroup(srcData As DataTable, rowGroupField As String, pivotColumnField As String, valueGroupFields As IEnumerable(Of String),
Optional ValueGroupColumnName As Func(Of String, String, String) = Nothing,
Optional otherFields As IEnumerable(Of String) = Nothing,
Optional GetOtherFieldValue As Func(Of DataTable, String, Object, Object) = Nothing
) As DataTable
Dim groupValueList As List(Of Object) = srcData.GetDistinctValuesByColumnName(rowGroupField)
Dim pivotValueList As List(Of Object) = srcData.GetDistinctValuesByColumnName(pivotColumnField)
Dim hasOtherFieldColumn As Boolean = Not (otherFields Is Nothing Or GetOtherFieldValue Is Nothing)
Dim dt As New DataTable
With dt
.Columns.Add(rowGroupField, srcData.Columns(rowGroupField).DataType)
For i As Integer = 0 To valueGroupFields.Count - 1
For j As Integer = 0 To pivotValueList.Count - 1
Dim columnName As String = GetColumnNameFromGroupFieldAndPivotValues(valueGroupFields(i), pivotValueList(j), ValueGroupColumnName)
dt.Columns.Add(columnName, srcData.Columns(valueGroupFields(i)).DataType)
Next
Next
If hasOtherFieldColumn Then
For i As Integer = 0 To otherFields.Count - 1
.Columns.Add(otherFields(i), srcData.Columns(otherFields(i)).DataType)
Next
End If
For i As Integer = 0 To groupValueList.Count - 1
Dim currentGroupValue As Object = groupValueList(i)
Dim dr As DataRow = dt.NewRow()
dr(rowGroupField) = currentGroupValue
If hasOtherFieldColumn Then
For j As Integer = 0 To otherFields.Count - 1
dr(otherFields(j)) = DBNullIfNothing(GetOtherFieldValue(srcData, otherFields(j), currentGroupValue))
Next
End If
For j As Integer = 0 To valueGroupFields.Count - 1
Dim currentField As String = valueGroupFields(j)
For k As Integer = 0 To pivotValueList.Count - 1
Dim currentPivotValue As Object = pivotValueList(k)
Dim columnName As String = GetColumnNameFromGroupFieldAndPivotValues(valueGroupFields(j), pivotValueList(k), ValueGroupColumnName)
Dim value As Object = (From row In srcData.AsEnumerable
Where row(rowGroupField) = currentGroupValue _
AndAlso row(pivotColumnField) = currentPivotValue
Select row(currentField)
).FirstOrDefault
dr(columnName) = DBNullIfNothing(value)
Next
Next
dt.Rows.Add(dr)
Next
End With
Return dt
End Function
<Extension()>
Public Function GetDistinctValuesByColumnName(dt As DataTable, columnName As String) As List(Of Object)
Dim valueList As List(Of Object) = (From row As DataRow In dt.AsEnumerable
Where Not IsDBNull(row(columnName))
Order By row(columnName)
Select row(columnName) Distinct
).ToList
Return valueList
End Function
Private Function GetColumnNameFromGroupFieldAndPivotValues(groupField As String, pivotValue As Object, Optional ValueGroupColumnName As Func(Of String, String, String) = Nothing) As String
Dim columnName As String = groupField & "_" & pivotValue.ToString()
If ValueGroupColumnName IsNot Nothing Then
columnName = ValueGroupColumnName(groupField, pivotValue)
End If
Return columnName
End Function
Public Function DBNullIfNothing(o As Object) As Object
If o Is Nothing Then Return DBNull.Value
Return o
End Function
And this is how I used the function to transform the table:
Dim chartData As DataTable = result.PivotDataTableColumnGroup("data_time", "hardware_id", {"ademand_im", "rdemand_im"}, Nothing, Nothing, Nothing)
ResultChartData = chartData 'Stored in ASPxHiddenField in JSON form
After that, instead of setting chart series properties in aspx file, I have to add chart series manually in code behind:
Private Sub chart_LoadProfile_DataBound(sender As Object, e As EventArgs) Handles chart_LoadProfile.DataBound
Using ResultChartData
Dim seriesList As List(Of String) = (From col As DataColumn In ResultChartData.Columns
Where col.ColumnName <> "data_time"
Order By col.ColumnName
Select col.ColumnName
).ToList
Dim hardWardCount As Integer = (From s In seriesList Where s.Contains("ademand_im_")).Count
Dim showInLegend As Boolean = hardWardCount > 1
With chart_LoadProfile.SeriesCollection
.Clear()
For i As Integer = 0 To seriesList.Count - 1
Dim fieldName As String = seriesList(i)
Dim hardwareId As String = seriesList(i).Split("_")(2)
Dim series As New BootstrapChartLineSeries
With series
.ArgumentField = "data_time"
.ValueField = fieldName
.Point.Size = 0
.ShowInLegend = showInLegend
If fieldName.Contains("ademand_im_") Then
.Pane = "A"
.Name = "kW - " & hardwareId
Else
.Pane = "B"
.Name = "kVar - " & hardwareId
End If
End With
.Add(series)
Next
End With
End Using
End Sub

Combine Row Cell for Repeater Record

I'm trying to combine the row cells when the campaign code and vehicle no are repeated as shown in below image. The result listed below is with gridview 20 page size
Problem
When the grid view page size is set with 2 for example, the row cell no longer combined. The result show each separated record.
If campaign code is sorted ascending/descending, the last record row cells will always not combine even though the campaign code and vehicle no are matched. Below image shown campaign code sorted in ascending. So when the campaign code is sorted descending, all the CMP002 are combined, while the last record of CMP001 will not be combined as shown in below image anymore.
Code Behind
Private Sub GV_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GV.RowDataBound
For rowIndex As Integer = GV.Rows.Count - 2 To 0 Step -1
Dim gvRow As GridViewRow = GV.Rows(rowIndex)
Dim gvPreviousRow As GridViewRow = GV.Rows(rowIndex + 1)
Dim sCurrCampaignCode As String = GV.DataKeys(rowIndex).Values("CAMPAIGN_CODE")
Dim sCurrVehicleNo As String = GV.DataKeys(rowIndex).Values("VEHICLE_NO")
Dim sPreviousCampaignCode As String = GV.DataKeys(rowIndex + 1).Values("CAMPAIG_CODE")
Dim sPreviousVehicleNo As String = GV.DataKeys(rowIndex + 1).Values("VEHICLE_NO")
If sCurrCampaignCode = sPreviousCampaignCode AndAlso sCurrVehicleNo = sPreviousVehicleNo Then
If sCurrCampaignCode = sPreviousCampaignCode Then
If gvPreviousRow.Cells(1).RowSpan < 2 Then
gvRow.Cells(1).RowSpan = 2
gvRow.Cells(2).RowSpan = 2
gvRow.Cells(3).RowSpan = 2
Else
gvRow.Cells(1).RowSpan = gvPreviousRow.Cells(1).RowSpan + 1
gvRow.Cells(2).RowSpan = gvPreviousRow.Cells(2).RowSpan + 1
gvRow.Cells(3).RowSpan = gvPreviousRow.Cells(3).RowSpan + 1
End If
gvPreviousRow.Cells(1).Visible = False
gvPreviousRow.Cells(2).Visible = False
gvPreviousRow.Cells(3).Visible = False
End If
End If
Next
End Sub
I just found a solution. Code have to be moved from RowDataBound to OnDataBound instead

Asp.Net GridView Retrieving cell values of each row through for loop and hiding empty columns

I know variations of this question have been asked a lot and I have been looking for answers for a long time and have tried many different blocks of code. Here is what I have right now which I am looping through from 0 to gridview1.rows.count-1. This code is in the RowDataBound Event.
Dim test As String
For i As Integer = 0 To GridView1.Rows.Count - 1
test = GridView1.Rows(i).Cells.Item(e.Row.RowIndex).Text.ToString
If test = " " Then
e.Row.Cells(i).Visible = False
End If
Next
Every time I get the error: Specified argument was out of the range of valid values.
Parameter name: index on this line
test = GridView1.Rows(i).Cells.Item(e.Row.RowIndex).Text.ToString
However, I think the error is just because I am going outside of the row range but can't figure out how to fix it. How can I successfully check each cell of all the rows and columns and hide the columns that return nothing.
I can now hide all of the actual cells within each column that is blank with this
Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs)
Dim GridView1 As GridView = FormView1.FindControl("GridView1")
For Each row As GridViewRow In GridView1.Rows
For i As Integer = 0 To row.Cells.Count - 1
Dim strtest As String = row.Cells(i).Text.ToString
If strtest = " " Then
row.Cells(i).Visible = False
End If
Next
Next
But it still won't let me hide the columns because with autogeneratecolumns it doesn't recognize that any columns are there so the code,
GridView1.Columns(i).visible = false
Throws the out of range error because there is no range of columns
For Each row As GridViewRow in GridView1.rows // rows
dim someval as String
for x= 0 to GridView1.Columns.Count // cols
if someval= = row.Cells[x].Text;
GridView1.Columns(x).Visible = false;
end if
next x
Next
manually typed pls check for typos'
Try something like this.
But I would probably point out that you seem to be reading through the entire grid every time you bind a row, which seems unnecessary. Rather you can have a separate method which you can call after the gridview is databound to hide your columns.
Put the below code in a function and call this function after the databinding for the grid.
Private Sub CheckForEmptyValues()
Dim dgv As DataGridView = GridView1
For r As Integer = 0 To dgv.RowCount - 1
For c As Integer = 0 To dgv.ColumnCount - 1
Dim cellValue as string = dgv.Rows(r).Cells(c).Value
If cellValue = " " Then
dgv.Rows(r).Cells(c).Visible = False
End If
Next
Next
End Sub
Ok Guys I finally found the correct way to do this, at least a way that works for me. So you have to use the row.cells.count -1 to actually get the count of your columns when you have autogeneratecolumns set to true and in order to iterate through your columns to set them to visible = false, you must use
GridView1.HeaderRow.Cells(i).visible = False
Here is my Final code and hopefully this will help a lot of people out that have the same problem, Thank you all for your help and answers
Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs)
Dim GridView1 As GridView = FormView1.FindControl("GridView1")
For Each row As GridViewRow In GridView1.Rows
For i As Integer = 0 To row.Cells.Count - 1
Dim strtest As String = row.Cells(i).Text.ToString
If strtest = " " Then
GridView1.HeaderRow.Cells(i).Visible = False
row.Cells(i).Visible = False
End If
Next
Next
End Sub

Command button with 'paste date' function to its next left cell

I'd like to create a Commandbutton with functionality to paste a date in to the cell to its left - I need to copy this button below in future.
I am trying:
Private Sub CommandButton2_Click()
Dim Str As String
Str = Date
Range(TopLeftCell).Value = Str
End Sub
I would recommend using Form Control instead of ActiveX control and the reason is very simple. When you copy the button across, the link to the macro remains intact., which is also one of your requirements.
And this is the code that you can use for the CommandButton (Form Control)
Sub Button1_Click()
Dim cellAddr As String
Dim aCol As Long
'~~> Get the address of the cell
cellAddr = ActiveSheet.Shapes(Application.Caller).TopLeftCell.Address
'~~> Also get the column number
aCol = ActiveSheet.Shapes(Application.Caller).TopLeftCell.Column
'~~> This is required if the button is in column 1
If aCol <> 1 Then _
ActiveSheet.Range(cellAddr).Offset(, -1).Value = Date
End Sub
To point at a specific range do something like this:
Private Sub CommandButton1_Click()
Dim Str As String
Str = Date
Range("C5").Value = Str
End Sub
Alternatively use a named range i.e. give the range C5 the name "TopLeftCell"
...then you can use the following:
Private Sub CommandButton1_Click()
Dim Str As String
Str = Date
Range("TopLeftCell").Value = Str
End Sub
Something like this:
Private Sub CommandButton2_Click()
Dim r As Long, c As Long, i As Long
Dim str As String
r = Rows.Count
c = Columns.Count
str = Date
For i = 1 To r
If Cells(i, 1).Top > CommandButton2.Top Then
Exit For
End If
Next
r = i - 1 ' you have to calibrate, what fits better r = i or r = i - 1 or r = i - 2 ....
For i = 1 To c
If Cells(1, i).Left > CommandButton2.Left Then
Exit For
End If
Next
c = i - 2 ' you have to calibrate, what fits better c = i or c = i - 1 or c = i - 2 ....
Cells(r, c) = str
End Sub
This should work, but it really depends on where you place the button. Look at the lines r = i - 1 and c = i - 2.

get the value from 2-d arraylist in session

I have an 2-d arraylist with 2 fixed columns and dynamic rows. The arraylist will be assigned to the session variable at the end of the code below. My question is how can loop thorugh the arraylist from the session to get its value?
If .SQLDS.Tables(.sSQLDSTbl).Rows.Count > 0 Then
Dim NoOfAdjType(1, .SQLDS.Tables(.sSQLDSTbl).Rows.Count - 1)
For iRow As Integer = 0 To .SQLDS.Tables(.sSQLDSTbl).Rows.Count - 1
If Not .SQLDS.Tables(.sSQLDSTbl).Rows(iRow).Item("i_commAmt") Is System.DBNull.Value Then
NoOfAdjType(0, iRow) = .SQLDS.Tables(.sSQLDSTbl).Rows(iRow).Item("productType")
NoOfAdjType(1, iRow) = Format(.SQLDS.Tables(.sSQLDSTbl).Rows(iRow).Item("i_commAmt"), "#,##0.00")
End If
Next
Session("iNoOfAdjAmtType") = NoOfAdjType
End If
I have tried this but it's giving me error 'Too many arguments to 'Public Overridable Default Property Item(index As Integer) As Object'
Dim NoOfAdjType As ArrayList = CType(Session("iNoOfAdjAmtType"), ArrayList)
For i As Integer = 0 To NoOfAdjType.Count
Dim a As String = NoOfAdjType(0, i)
Dim b As String = NoOfAdjType(1, i)
Next
The type you are dealing with is Object(,). So when reading from the session you can cast it back to this type.
Here's an article on MSDN which illustrates how to read values from session:
Dim NoOfAdjType as Object(,) = CType(Session("iNoOfAdjAmtType"), Object(,))
' do something with the list
And if you wanted to perform the check safely ensuring that there is an item with the given id in the session:
If Session.Item("iNoOfAdjAmtType") IsNot Nothing Then
' We have a value in the session with the given id
Dim NoOfAdjType as Object(,) = CType(Session("iNoOfAdjAmtType"), Object(,))
End If
I am not certain what is the data-type of array, but this how you manipulate the multi-dimension arrays in VB.NET assuming data-type as object
' declaring variable of multi-dim array
Dim NoOfAdjType As Object(,)
' create array object of needed dimension (you may use redim keyword)
NoOfAdjType = new Object(1, .SQLDS.Tables(.sSQLDSTbl).Rows.Count - 1) {}
...
' push it in session
Session("iNoOfAdjAmtType") = NoOfAdjType
...
' get back from session
NoOfAdjType = DirectCast(Session("iNoOfAdjAmtType"), Object(,))
...
For i As Integer = 0 To NoOfAdjType.GetLength(0)
For j As Integer = 0 To NoOfAdjType.GetLength(1)
Dim a As Object = NoOfAdjType(i, j);
...
Next
Next
See this MSDN article for array in VB.NET: http://msdn.microsoft.com/en-us/library/wak0wfyt.aspx
Try this,
Dim a As String = NoOfAdjType(0)(0,0)
Or use
For Each arr As Object(,) In NoOfAdjType
Next

Resources