Can any one help me to create group alphabet gridview to look like this picture?
I've tried with this code, but rows are not grouped by alphabet.
Private Sub GridView1_CustomColumnDisplayText(sender As Object, e As CustomColumnDisplayTextEventArgs) Handles GridView1.CustomColumnDisplayText
If e.Column.FieldName = "CompanyName" AndAlso e.IsForGroupRow Then
Dim rowValue As String = GridView1.GetGroupRowValue(e.GroupRowHandle, e.Column)
Dim val As String = Microsoft.VisualBasic.Left(rowValue, 1)
e.DisplayText = val
End If
End Sub
There is no need to handle the CustomColumnDisplay text event handler to extract the first letter of the "CompanyName" value. Instead, simply set the GridColumn.GroupInterval property for the "CompanyName" GridColumn to "Alphabetical". For instance:
MyGridView.Columns("CompanyName").GroupInterval = ColumnGroupInterval.Alphabetical
Related
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
This is how the Order History looks like:
What I want to do is sort the items in this ListView by Date.
So far, I can't find any useful resource materials where I can sort the items by date.
Private Sub frmOrderHistory_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim orders As String = WindowsApplication1.Class1.Orders
Dim arrCheck(3) As String
Dim lineNum As Integer = -1
For Each i As String In System.IO.Directory.GetFiles(orders)
Dim a, c As String
a = System.IO.Path.GetFileNameWithoutExtension(i)
c = System.IO.Path.GetFullPath(i)
For Each line As String In File.ReadLines(c)
lineNum = lineNum + 1
ListView1.Items.Add(a)
arrCheck = Split(line, ",")
ListView1.Items(lineNum).SubItems.Add(arrCheck(0))
ListView1.Items(lineNum).SubItems.Add(arrCheck(1))
Next
Next
End Sub
The solution to your problem is to create list of objects which you want to display in the list view, sort the listview as per the requirement and then use the sorted list to the display in the list view.
I suggest to create a class Order to collect the order details from the file. Create list of orders and sort the list and then display it in the list view as following.
Following is the class Order.
Public Class Order
Public Property OrderDate() As DateTime
Get
Return m_OrderDate
End Get
Set
m_OrderDate = Value
End Set
End Property
Private m_OrderDate As DateTime
Public Property Item() As String
Get
Return m_Item
End Get
Set
m_Item = Value
End Set
End Property
Private m_Item As String
Public Property Price() As Double
Get
Return m_Price
End Get
Set
m_Price = Value
End Set
End Property
Private m_Price As Double
End Class
Following is the code of list binding.
Private Sub frmOrderHistory_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim orders As String = WindowsApplication1.Class1.Orders
Dim arrCheck(3) As String
Dim orderList = New List(Of Order)()
For Each filePath As var In System.IO.Directory.GetFiles(orders)
Dim order = New Order()
order.OrderDate = DateTime.ParseExact(System.IO.Path.GetFileNameWithoutExtension(filePath), "dd-MM-yyyy", CultureInfo.InvariantCulture)
For Each line As var In System.IO.File.ReadAllLines(filePath)
arrCheck = line.Split(New Char() {","C})
order.Item = arrCheck(0)
order.Price = Convert.ToDouble(arrCheck(1))
orderList.Add(order)
Next
Next
Dim sortedOrder = orderList.OrderByDescending(Function([or]) [or].OrderDate).ToList()
For i As var = 0 To sortedOrder.Count - 1
listView1.Items.Add(sortedOrder(i).OrderDate.ToString("dd-MM-yyyy"))
listView1.Items(i).SubItems.Add(sortedOrder(i).Item)
listView1.Items(i).SubItems.Add(sortedOrder(i).Price.ToString("00.00"))
Next
End Sub
As you can observer this solution is not straight forward. It requires formatting of string to datetime and back to string. The same with double values. Also requires looping thru items more than once.
Simpler would be to use datagridview. It takes a few clicks to set columns and dataformats of columns if you use datagridview. And you can bind collection of orders directly to it without looping thru the collection as following.
DataGridView1.DataSource = sortedOrder;
I want to add the following combobox items into the array called "Numbers". Below is what I have so far. How do I add each combobox item into the array? Thanks.
number.Items.Add("One")
number.Items.Add("Two")
number.Items.Add("Three")
number.Items.Add("Four")
number.Items.Add("Five")
number.Items.Add("Six")
number.Items.Add("Seven")
Dim Numbers(6) As String
Dim count As Integer
For count= 0 To 6
Numbers(count) = number.Text
Next count
Try this code (it convert all items to array of string, so You can skip defining array size) :
number.Items.Add("One")
number.Items.Add("Two")
number.Items.Add("Three")
number.Items.Add("Four")
number.Items.Add("Five")
number.Items.Add("Six")
number.Items.Add("Seven")
'convert all items to string array
Dim Numbers = number.Items.Cast(Of String).ToArray()
you're very nearly there..
Dim Numbers(6) As String
Dim count As Integer
For count = 0 To 6
Numbers(count) = Number.Items(count).ToString
Next count
End Sub
I would use CopyTo() built-in method
Dim Numbers(ComboBox1.Items.Count - 1) As String
ComboBox1.Items.CopyTo(Numbers, 0)
The usual way round would be to put the items into an array and then either use that as the datasource for the combobox or simply add them with .AddRange:
Public Class Form1
Dim numbers As String()
Private Sub SetUpNumberComboBox()
numbers = {"One", "Two", "Three", "Four", "Five", "Six", "Seven"}
number.Items.AddRange(numbers)
' alternatively:
'number.DataSource = numbers
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetpUpNumbersComboBox()
End Sub
End Class
[For anyone who uses the designer to add items, that way, you don't need to go through the (relatively) fiddly designer to change the items, you just edit the code.]
Since i needed to disable (grey out) some items inside a ListBox, i'm using a Custom control that can be found here:
Here is my current code:
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dtp.Columns.Add("key")
dtp.Columns.Add("value")
PopulateDataTable(dtp, "myTxt")
_dataView = New DataView(dtp)
'Custom ListBox
List1.ValueMember = "key"
List1.DisplayMember = "value"
List1.DataSource = _dataView
'Legacy ListBox
List2.ValueMember = "key"
List2.DisplayMember = "value"
List2.DataSource = _dataView
UpdateLanguageMenu()
End Sub
Private Function PopulateDataTable(dt As DataTable, resTxt As String)
Using sw As New StringReader(My.Resources.ResourceManager.GetObject(resTxt))
Do
Dim line As String = sw.ReadLine
If line Is Nothing OrElse line.Trim = String.Empty Then Exit Do
Dim strArr() As String
strArr = line.Split(",")
Dim row As DataRow = dt.NewRow()
row("key") = strArr(0)
row("value") = strArr(1)
dt.Rows.Add(row)
Loop
sw.Close()
End Using
End Function
List1 is the Custom ListBox and List2 is the ListBox that comes with VS2012E.
I don't need List2, it's only there to test,
and at runtime, in List2 i get all my values loaded correctly, instead in List1 i get System.Data.DataRowView in all rows..
The strange thing is that, my txt i'm loading is like:
00A1,MyValue1
00A2,Myvalue2
00A3,MyValue3
I have also a Label, and when selecting items on the ListBox i have code to change the Label.Text to List.SelectedValue that is the first part before the comma.
And it get displayed in the label. Only items inside the Custom ListBox are not being displayed.
Populating List1 manually, instead using a DataTable, is working.
And since i'm a beginner i can't locate the problem.
I think your problem has to do with this line: string displayValue = GetItemText(item); in the control. This takes for granted that all items are strings. In your case it is a datarowview hence the result (drv.toString would return something like that). You need to convert "item" into a drv and set display value to be drvItem("value" or "key") instead. So it is basically not your code that is the problem, it is the control.
Actually... After reading the code in the control and not on the code project site, I realised that this line:
displayValue = GetItemText(item);
Doesn't even exist. It is exchanged with
item.ToString()
Which pretty much proves my theory.
Right, how to fix.
In:
protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
You have this:
object item = this.Items[e.Index];
What you have to do is to convert item into a DataViewRow and assign value to a variable, something like this:
DataViewRow dvrItem = (DataViewRow)item;
String displayText = dvrItem("key"); or String displayText = dvrItem("value");
Then change all these:
e.Graphics.DrawString(item.ToString(), e.Font, SystemBrushes.GrayText, e.Bounds);
Into:
e.Graphics.DrawString(displayText, e.Font, SystemBrushes.GrayText, e.Bounds);
I'm close to getting this to work, but currently can't get any output to display in the listbox. I had it working, but needed to move some things around to get the join function to work.
In my program, a user enters input into a textbox and an array is displayed in a listbox based on what they type in. For example, if they type in "a", all foods (in the textfile that is connected to the program) that start with "a" will be displayed.
When there is output, I need to find a way to name this array (which is created based on what the user inputs) and join all of the items in the listbox (example: foods stacked on top of each other in the listbox will be shown at the bottom as a string).
I am posting the code that I have thus far; all of the errors that I'm getting (and potentially my logic errors) are just in the first public class until the end of the first if-next statement:
Public Class frmFoods
Dim foods() As String = IO.File.ReadAllLines("foods.txt")
Private Sub btnDisplay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisplay.Click
Dim Letter As String = txtLetter.Text.ToUpper
Dim smallerarray() As Array
Dim userarray As String
lstOutput.Items.Clear()
If IsNumeric(txtLetter.Text) = False Then
For Each food As String In foods
smallerarray = listfoods(Letter)
lstOutput.Items.Add(Letter)
userarray = Join(smallerarray, ", ")
lstOutput.Items.Add(userarray)
Next
ElseIf IsNumeric(txtLetter.Text) = True Then
MessageBox.Show("Please enter a letter.")
Else
MessageBox.Show("The text box is empty")
End If
End Sub
Function listfoods(ByVal letter As String) As String()
Dim foodarray(foods.Count - 1) As String
Dim counter As Integer = 0
For Each food As String In foods
If food.StartsWith(letter) Then
foodarray(counter) = food
counter += 1
End If
Next
ReDim Preserve foodarray(counter - 1)
Return foodarray
End Function
you need to save the results of the listfoods function in a dictionary or similar and associate it with a key if you want to 'Name' it, although its not clear why you need to do this
As for listing the foods starting with the particular letter, you just need to iterate your result of the function listfoods and separate each one by a comma don't you?
What you have now will create many lists of each food as you are getting the list of food beginning with a particular letter for each food.. As I understand the question you only need to do that once.
Example:
Private Sub btnDisplay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisplay.Click
Dim Letter As String = txtLetter.Text.ToUpper
Dim smallerarray() As Array
Dim userarray As String
lstOutput.Items.Clear()
If IsNumeric(txtLetter.Text) = False Then
'get all items from the file which begin with the letter the user chose
smallerarray = listfoods(Letter)
'add that letter to the output listbox
lstOutput.Items.Add(Letter)
'join all of the elements which begin with that letter
'into a single comma separated string
userarray = Join(smallerarray, ", ")
'add that string to the output
lstOutput.Items.Add(userarray)
ElseIf IsNumeric(txtLetter.Text) = True Then
MessageBox.Show("Please enter a letter.")
Else
MessageBox.Show("The text box is empty")
End If
End Sub
it would probably be useful for you to step through the code and see the values of the variable at each place and compare this with what you expect to see if you can see where the actual value differs from what your logically expect so you can start to identify where the issue is