Have the following code which creates a table of all the images in a folder.
VB:
Sub Page_Load(sender as Object, e as EventArgs)
If Not Page.IsPostBack then
Dim dirInfo as New DirectoryInfo(Server.MapPath("/images"))
articleList.DataSource = dirInfo.GetFiles("*.jpg")
articleList.DataBind()
End If
End Sub
Body:
<asp:DataGrid runat="server" id="articleList" AutoGenerateColumns="False" ShowHeader="false">
<Columns>
<asp:BoundColumn DataField="Name" />
</Columns>
</asp:DataGrid>
The results look something like this:
aa_01.jpg
aa_02.jpg
aa_03.jpg
bb_01.jpg
bb_02.jpg
cc_01.jpg
cc_02.jpg
cc_03.jpg
cc_04.jpg
...
What I want to do now is group all these by the first two characters and get the total number for each and insert them into individual strings. So for the above example it would be something like:
Dim aa As String = 3
Dim bb As String = 2
Dim cc As String = 4
Any ideas how?
You can do this using Linq. Try this.
dim q = From p in articles _
Group By Name = p.Name.SubString(0,2) into g = group _
Select GroupName = Name, _
Count = g.Count()
Update (to give a bit of context as per comments)
Sub Page_Load(sender as Object, e as EventArgs)
If Not Page.IsPostBack then
Dim dirInfo as New DirectoryInfo(Server.MapPath("/images"))
Dim articles = dirInfo.GetFiles("*.jpg")
articleList.DataSource = articles
articleList.DataBind()
Dim groupings = From p in articles _
Group By Name = p.Name.SubString(0,2) into g = group _
Select GroupName = Name, _
Count = g.Count()
' do whatever you like with the groupings '
End If
End Sub
In C#, using LINQ:
groupedArticleList = (from a in articleList
group a by a.Name.Substring(0, 2) into g
select new
{
GroupName = g.Key,
ArticleCount = g.Count()
});
You can't really extract them into separate variables but you could use groupedArticleList as-is and loop through it or convert it to a Dictionary<string, int>.
Sorry I don't know the VB syntax but hopefully that will help.
Related
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
Can anyone please tell me how to get value from datatable? I've only got one row and one column in the datatable and I need to get the value of the column to do calculations.
here's my script
<SCRIPT Language="VB" Runat="server">
Sub Page_Load(Source as object, e as EventArgs) handles me.load
Dim connectionstring As String = "DRIVER={MySQL ODBC 5.2 Unicode Driver}; SERVER=localhost; DATABASE=mydb; UID=andrew; PASSWORD=kh12345; OPTION=3"
Dim connectme As OdbcConnection = New OdbcConnection(connectionstring)
Dim sqlquery As String = "SELECT f_name, f_price from tbl_picture WHERE f_ID = 1"
Dim ODBCdataadapter As OdbcDataAdapter = New OdbcDataAdapter(sqlquery, connectme)
Dim ODBCdataset As DataSet = New DataSet()
ODBCdataadapter.Fill(ODBCdataset)
DataTable.DataSource = ODBCdataset
DataTable1.DataSource = ODBCdataset
Datatable.DataBind()
Datatable1.DataBind()
End Sub
</SCRIPT >
<ASP:Datagrid ID="Datatable1" Runat="server" AutoGenerateColumns="False"BorderStyle="None" GridLines="None">
<Columns>
<asp:BoundColumn
DataField="f_price"
ReadOnly="True"/>
</columns>
</asp:DataGrid>
and here's the calculation part
Private Sub CalculatePayment()
Dim c_loan_amount, c_Payment
Dim amount As String = Datatable1.Select("f_price")
c_loan_amount = amount - (amount * Down.Text * 0.01)
c_Payment = ((c_loan_amount * (Interest.Text * 0.01) * Year.Text) + c_loan_amount) / (Year.Text * 12)
Payment.Text = "RM " & Format(c_Payment, "#,##0.00")
End Sub
It should be the Dim amount as string part right? I'm kinda new, thanks in advance.
You need to define the row and item.
Try
Dim amount As String = Datatable1.tables(0).Rows(0).Item(1)
Actually you should rename datatable1 to dataset1 since a datatable is a possible member of a dataset. Its just to minimize confusion of what is what.
The Rows tells which row of the datatable. The item tells which index.
0 = f_name
1 = f_amount
I am adding multiple controls dynamically based on a dropdownlist that the user selects. i.e. if the user selects 3 then 3 sets of the controls are added. My problem is not in adding the controls, I can add them fine, I haven't added all my code but the main parts to understand what I am doing.
Once the controls have been created, the relevant info is captured. On the Update click I need to access the values of these dynamic controls by looping through in the correct order and retrieve the values and write to the database. I can't seem to access them correctly.
Hopefully I am making sense. Any help would be appreciated. Thanks
''Loop through first set of controls and get values and then the next set etc..
Dim Description as string = ''Get Textbox value
Dim Type as string = ''Get RadComboBox value
Dim XFieldName as string = ''Get RadComboBox value
Dim Colour as string = ''Get RadColorPicker value
Below is my Code:
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
RecreateControlsTxt("txt", "TextBox")
RecreateControlsChart("comboChart", "RadComboBox")
RecreateControls("combo", "RadComboBox")
RecreateControlsCP("cp", "RadColorPicker")
End Sub
Protected Sub AddControls_Click(sender As Object, e As EventArgs) Handles AddControls.Click
For i As Integer = 0 To ddlFieldNames.SelectedIndex
CreateTextbox("txt-" & Convert.ToString(i + 1))
Next
For i As Integer = 0 To ddlFieldNames.SelectedIndex
CreateComboChart("comboChart-" & Convert.ToString(i + 1))
Next
For i As Integer = 0 To ddlFieldNames.SelectedIndex
CreateComboField("combo-" & Convert.ToString(i + 1))
Next
For i As Integer = 0 To ddlFieldNames.SelectedIndex
CreateColourPicker("cp-" & Convert.ToString(i + 1))
Next
End Sub
Private Sub CreateTextbox(ByVal ID As String)
Dim txt As New TextBox()
txt.ID = ID
txt.Height = 20
Me.divDesc.Controls.Add(txt)
End Sub
Private Sub CreateComboField(ByVal ID As String)
Dim combo As New RadComboBox()
combo.ID = ID
combo.DataSource = Me.odsChartsSeriesField
combo.DataTextField = "FieldNames"
combo.DataValueField = "FieldNames"
combo.DataBind()
Me.divField.Controls.Add(combo)
End Sub
Private Sub CreateComboChart(ByVal ID As String)
Dim comboChart As New RadComboBox()
comboChart.ID = ID
Dim item1 As New RadComboBoxItem()
item1.Text = "Line"
item1.Value = "smoothedLine"
item1.ImageUrl = ("Images/linechart.png")
comboChart.Items.Add(item1)
Dim item2 As New RadComboBoxItem()
item2.Text = "Column"
item2.Value = "column"
item2.ImageUrl = ("Images/bar chart.png")
comboChart.Items.Add(item2)
Dim item3 As New RadComboBoxItem()
item3.Text = "Pie"
item3.Value = "pie"
item3.ImageUrl = ("Images/pie chart.jpg")
comboChart.Items.Add(item3)
Me.divChart.Controls.Add(comboChart)
End Sub
Private Sub CreateColourPicker(ByVal ID As String)
Dim cp As New RadColorPicker()
cp.ID = ID
cp.ShowIcon = True
cp.Style("padding-top") = "1px"
cp.CssClass = "CustomHeight"
Me.divCol.Controls.Add(cp)
End Sub
Protected Sub Update_Click(sender As Object, e As EventArgs) Handles Update.Click
Try
Dim alltxt = divDesc.Controls.OfType(Of TextBox)()
Dim allcomboChart = divChart.Controls.OfType(Of RadComboBox)()
Dim allcomboField = divField.Controls.OfType(Of RadComboBox)()
Dim allcp = divCol.Controls.OfType(Of RadColorPicker)()
''Loop through first set of controls and get values and then the next etc..
Dim Description as string = ''Get Textbox value
Dim Type as string = ''Get RadComboBox value
Dim XFieldName as string = ''Get RadComboBox value
Dim Colour as string = ''Get RadColorPicker value
If Page.IsValid Then
Dim da As New dsSVTableAdapters.Chart
Dim Result As String = da.Series(60, Description, Type, Colour, "YFieldName", XFieldName)
End If
Catch ex As Exception
lblResult.Text = ex.Message
End Try
End Sub
You have a repeated set of controls. Therefore you need a corresponding repeated set of variables that store these values.
I suggest creating a class where you can store a variable (or property) set.
Public Class ControlSet
Public Property Description As String
Public Property Type As String
Public Property XFieldName As String
Public Property Colour As String
End Class
Create an array that holds these values
Dim Values = New ControlSet(ddlFieldNames.SelectedIndex) {}
And retrieve the values in a loop
For i As Integer = 0 To Values.Length - 1
Values(i).Description = CType(divDesc.FindControl("txt-" & Convert.ToString(i + 1)), TextBox).Text
Values(i).Type = CType(divChart.FindControl("comboChart-" & Convert.ToString(i + 1)), RadComboBox).SelectedValue
Values(i).XFieldName = ...
...
Next
Also use the ID of the control; this helps to avoid confusion in case you have several controls of the same type.
you can use .FindControl(string id) method, and you should keep the controls count in your view state or session:
Protected Sub Update_Click(sender As Object, e As EventArgs) Handles Update.Click
Try
''Loop through first set of controls and get values and then the next etc..
For i As Integer = 0 To controlsCount - 1
Dim Description as string = ((TextBox)divDesc.FindControl("txt-" & Convert.ToString(i + 1))).Text ''Get Textbox value
Dim Type as string = ((RadComboBox)divChart.FindControl("comboChart-" & Convert.ToString(i + 1))).SelectedValue ''Get RadComboBox value
Dim XFieldName as string = ((RadComboBox)divField.FindControl("combo-" & Convert.ToString(i + 1))).SelectedValue ''Get RadComboBox value
Dim Colour as string = ((RadColorPicker)divField.FindControl("cp-" & Convert.ToString(i + 1))).SelectedValue ''Get RadColorPicker value
If Page.IsValid Then
Dim da As New dsSVTableAdapters.Chart
Dim Result As String = da.Series(60, Description, Type, Colour, "YFieldName", XFieldName)
Next
End If
Catch ex As Exception
lblResult.Text = ex.Message
End Try
End Sub
I have two questions.
How do I construct my XML- file which i want to output in a Stacked Column chart using the code-behind?
And secondly,
How do I put it in the code-behind in vb?
This is the code-behind at the moment:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Chart1.Width = 200
Chart1.Height = 300
Dim XMLFile As XElement = XElement.Load(Server.MapPath("~/xml/XMLFile.xml"))
Chart1.Series(0).ChartType = DataVisualization.Charting.SeriesChartType.StackedColumn
Chart1.Series(0).Palette = DataVisualization.Charting.ChartColorPalette.BrightPastel
Chart1.Series("Series1").IsValueShownAsLabel = True
For Each node As XElement In XMLFile.Elements("something")
Dim string1 As String = node.Element("whatever1").Value
Dim string2 As String = node.Element("whatever2").Value
Chart1.Series("Series1").Points.AddXY(string1, string2)
Chart1.ChartAreas("ChartArea1").Area3DStyle.Enable3D = True
Chart1.ChartAreas("ChartArea1").Area3DStyle.Inclination = 15
Chart1.ChartAreas("ChartArea1").Area3DStyle.Rotation = 15
Next
End Sub
The XMLFile looks something like this at the moment:
<root>
<something>
<whatever1>One</whatever1>
<whatever2>1</whatever2>
</something>
<something>
<whatever1>Two</whatever1>
<whatever2>2</whatever2>
</something>
</root>
I need two columns with three different values stacked in each column.
How do I do that?
I am trying to to loop through a dataset's value through the rows in a gridview and color in the text if that row matches.
The code below works however whenever I change the page through the PageIndexChanging and this function is ran again, the coloring doesn't work anymore. It still loops through the gridview if there is a match but the effects are not shown.
--variable initialization class instantiation--
--code to connect to db here--
mySQLCommand.CommandText = "SELECT ..."
mySQLAdapter = New SqlDataAdapter(mySQLCommand)
mySQLAdapter.Fill(myDataset)
Me.MainPageGridView.DataSource = myDataset
Me.MainPageGridView.DataBind()
mySQLCommand.CommandText = "SELECT ... The ID's to be matched"
mySQLAdapter = New SqlDataAdapter(mySQLCommand)
mySQLAdapter.Fill(myDatasetNew)
Me.MainPageGridView.DataSource = myDatasetNew
For Each dataRow In myDataset.Tables(0).Rows
thisID = dataRow("ID").ToString
For Each gvRow In Me.MainPageGridView.Rows
If gvRow.Cells(2).Text = thisID Then
For column = 0 To 14 Step 1
gvRow.Cells(column).ForeColor = Drawing.Color.RosyBrown
Next
Exit For
End If
Next
Next
Why don't you use MainPageGridView_RowDataBound event to match the id? I have re-factored your original code to something like below, please check and let me know if it works:
'In DataBind or some other method
'Load(myDataSet)
mySQLCommand.CommandText = "SELECT ..."
mySQLAdapter = New SqlDataAdapter(mySQLCommand)
mySQLAdapter.Fill(myDataset)
'Load myDatasetNew and bind it to grid
mySQLCommand.CommandText = "SELECT ... The ID's to be matched"
mySQLAdapter = New SqlDataAdapter(mySQLCommand)
mySQLAdapter.Fill(myDatasetNew)
Me.MainPageGridView.DataSource = myDatasetNew
Me.MainPageGridView.DataBind()
and perform id matching in
Protected Sub MainPageGridView_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles MainPageGridView.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim id As String = DataBinder.Eval(e.Row.DataItem, "ID") 'The name of ID column in "myDatasetNew"
Dim dv As System.Data.DataView = myDataset.Tables(0).DefaultView
dv.RowFilter = "ID = " & id
If dv.Count > 0 Then 'id matches
'Change foreclor of entire row
e.Row.ForeColor = Drawing.Color.RosyBrown
End If
End If
End Sub
You really need to do your data comparison in the GridView.RowDataBound event.