VB.NET using LINQ to transpose an ObservableCollection - wpf

I have a custom item class (basically two string values with associated properties), as below:
Public Class itmDataDetails
Private _strDataName As String
Private _strDataValue As String
Public Property strDataName() As String
Get
Return _strDataName
End Get
Set(ByVal value As String)
_strDataName = value
End Set
End Property
Public Property strDataValue() As String
Get
Return _strDataValue
End Get
Set(ByVal value As String)
_strDataValue = value
End Set
End Property
Public Sub New(Optional ByVal strDataNameIn As String = "", Optional ByVal strDataValueIn As String = "")
strDataName = strDataNameIn
strDataValue = strDataValueIn
End Sub
and an ObservableCollection wrapper class around this. I'd like to transpose this ObservableCollection (that is, make the data names into the columns and their associated values into the rows) for display in a WPF ListView.
Here's what I have so far:
Private Sub Transpose()
Dim colGroupedValues = From x In MyBase.Items Group x By Key = x.strDataName Into Group Select strName = Key, colValues = Group
MyBase.Clear()
For Each x In colGroupedValues
MyBase.Add(x)
Next
End Sub
Naturally, this doesn't work as x cannot be added to the ObservableCollection(Of itmDataDetails). Any suggestions on how to accomplish this? I don't know LINQ that well, so I wouldn't be surprised to discover I'm doing it wrong.
Thanks in advance, everyone.

So I think I was asking the wrong question here. What I really wanted was to have each column in a GridView be set to the DataName part of itmDataDetails and its corresponding records be set to the DataValue.
To do this, I followed the helpful guide at: http://weblogs.asp.net/psheriff/archive/2010/03/08/using-a-wpf-listview-as-a-datagrid.aspx
So the whole thing is replaced by:
Private Sub FillDataList()
Dim strConnectionString As String = "INSERT CONNECTION INFO HERE"
Dim strCommandString As String = "INSERT QUERY HERE"
Dim objCommand As New OleDb.OleDbCommand(strCommandString)
Dim objConnection As New OleDb.OleDbConnection(strConnectionString)
Dim objAdapter As New OleDb.OleDbDataAdapter
Dim ds As New DataSet
objConnection.Open()
objAdapter.SelectCommand = objCommand
objCommand.Connection = objConnection
objAdapter.Fill(ds)
lsvData.View = BuildDataView(ds)
lsvData.DataContext = ds.Tables(0)
lsvData.SetBinding(ListView.ItemsSourceProperty, New Binding)
objConnection.Close()
End Sub
Public Function BuildDataView(ByVal ds As DataSet) As GridView
Dim gv As New GridView
For Each item As DataColumn In ds.Tables(0).Columns
Dim gvc As New GridViewColumn
gvc.DisplayMemberBinding = New Binding(item.ColumnName)
gvc.Header = item.ColumnName
gvc.Width = [Double].NaN
gv.Columns.Add(gvc)
Next
Return gv
End Function
This gives me what I wanted. Sorry for the misunderstanding, if there was any. I'll still accept an answer that does this task better than my solution (to be charitable, etc.)
I also suspect that the database engine doesn't matter here, so you could probably do something similar for Oracle databases, etc.

Related

Unable to WRAP text in an Autocomplete Textbox column of DataGridView

I created an Autocomplete Textbox column in DataGridView (Works Fine).
See this image. This is what I have
Now there is no problem until the text size is small but when the text gets longer it doesn't get wrapped in the column, the text gets trimmed.
This is the Problem
If I set the WRAP property of the column to TRUE then the textbox stops Autocompleting.
SO, its like either auto-completing or WRAPPING, but I need both...
I am putting my code below if anything can be done within it, have a look -
Private Sub DataGridView2_EditingControlShowing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView2.EditingControlShowing
DataGridView2.BeginEdit(True)
Dim autoText As TextBox = TryCast(e.Control, TextBox)
If autoText IsNot Nothing Then
autoText.AutoCompleteMode = AutoCompleteMode.SuggestAppend
autoText.AutoCompleteCustomSource = AutoCompleteLoad()
autoText.AutoCompleteSource = AutoCompleteSource.CustomSource
End If
End Sub
Public Function AutoCompleteLoad() As AutoCompleteStringCollection
Dim str As AutoCompleteStringCollection = New AutoCompleteStringCollection()
Dim ConnectionString As SqlConnection = New SqlConnection("data source=ADMIN-PC\SQLEXPRESS; database=billdev;Trusted_Connection=yes;")
Dim strSQL As String = "SELECT particulars from bill;"
Dim SQLcommand As New SqlCommand(strSQL, ConnectionString)
ConnectionString.Open()
Dim reader As SqlDataReader
reader = SQLcommand.ExecuteReader()
While reader.Read()
str.Add(reader.Item(0))
End While
Return str
End Function
[SOLVED]
Maybe it has a bug in datagridview control.
we can do one cheat method to solve this issue.
in Datagridview_CellBegainEdit, set rowsDefaultcellstyle wrapmode = false
in DatagridView_CellEndEdit, set rowsDefaultcellstyle wrapmode = true
Example:
DGV.RowsDefaultCellStyle.WrapMode = DataGridViewTriState.False (CellBegainEdit)
DGV.RowsDefaultCellStyle.WrapMode = DataGridViewTriState.True (CellEndEdit)
Its working for me.

(VB.NET) display the lower half of a textfile to a listbox

I have to make a application that organizes a list of runners and their teams. In the following text file, I have to remove the top half of the text file (the top half being the listed teams) and display only the bottom half (the runners)in a listbox item.
The Text file:
# School [School Code|School Name|Coach F-Name|Coach L-Name|AD F-Name|AD L Name]
WSHS|Worcester South High School|Glenn|Clauss|Bret|Zane
WDHS|Worcester Dorehty High School|Ellsworth|Quackenbush|Bert|Coco
WBCHS|Worcester Burncoat High School|Gail|Cain|Kevin|Kane
QRHS|Quabbin Regional High School|Bob|Desilets|Seth|Desilets
GHS|Gardner High School|Jack|Smith|George|Fanning
NBHS|North Brookfield High School|Hughe|Fitch|Richard|Carey
WHS|Winchendon High School|Bill|Nice|Sam|Adams
AUBHS|Auburn High School|Katie|Right|Alice|Wonderland
OXHS|Oxford High School|Mary|Cousin|Frank|Daughter
# Roster [Bib #|School Code|Runner's F-Name|Runner's L-Name]
101|WSHS|Sanora|Hibshman
102|WSHS|Bridgette|Moffitt
103|WSHS|Karine|Chunn
104|WSHS|Shanita|Wind
105|WSHS|Fernanda|Parsell
106|WSHS|Albertha|Baringer
107|WSHS|Carlee|Sowards
108|WDHS|Maisha|Kleis
109|WDHS|Lezlie|Berson
110|WDHS|Deane|Rocheleau
111|WDHS|Hang|Hodapp
112|WDHS|Zola|Dorrough
113|WDHS|Shalon|Mcmonigle
I have some code that reads each row from the text file as an array and uses boolean variables to determine where to end the text file. This worked with displaying only the teams, which I've managed to do. But I now need to do the opposite and display only the players, and I'm a bit stumped.
My Code:
Private Sub btnLoadTeams_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadTeam.Click
' This routine loads the lstTeam box from an ASCII .txt file
' # School [School Code | Name | Coach F-Name| Coach L-Name | AD F-Name | AD L-Name]
Dim strRow As String
Dim bolFoundCode As Boolean = False
Dim bolEndCode As Boolean = False
Dim bolFoundDup As Boolean = False
Dim intPosition As Integer
Dim intPosition2 As Integer
Dim strTeamCodeIn As String
Dim textIn As New StreamReader( _
New FileStream(txtFilePath.Text, FileMode.OpenOrCreate, FileAccess.Read))
' Clear Team listbox
lstTeam.Items.Clear()
btnDeleteRunner.Enabled = True
Do While textIn.Peek <> -1 And Not bolEndCode
Me.Refresh()
strRow = textIn.ReadLine.Trim
If Not bolFoundCode Then
If "# SCHOOL " = UCase(Mid(strRow, 1, 9)) Then
bolFoundCode = True
End If
Else
If Mid(strRow, 1, 2) <> "# " Then
For Each item As String In lstTeam.Items
intPosition = InStr(1, strRow, "|")
strTeamCodeIn = Mid(strRow, 1, intPosition - 1)
intPosition2 = InStr(1, item, strTeamCodeIn)
If intPosition2 > 0 Then
bolFoundDup = True
MsgBox("Found Duplicate School Code: " & strTeamCodeIn)
End If
Else
bolEndCode = True
Next
If Not bolFoundDup Then
lstTeam.Items.Add(strRow)
Else
lstTeam.Items.Add("DUPLICATE School Code: " & strRow)
lstTeam.Items.Add("Please correct input file and reload teams")
bolEndCode = True
End If
End If
End If
Loop
End Sub
Ive put bolEndCode = True in between the part that reads the mid section of the text file, but all Ive managed to display is the following in the listbox:
# Roster [Bib #|School Code|Runner's F-Name|Runner's L-Name]
Any help or hints on how I would display just the runners to my "lstPlayers" listbox would be greatly appreciated. I'm a beginner programmer and We've only just started learning about reading and writing arrays in my .NET class.
First I made 2 classes, one Runner and one School. These have the properties available in the text file. As part of the class I added a function that overrides .ToString. This is for he list boxes that call .ToString for display.
Next I made a function that reads all the data in the file. This is very simple with the File.ReadLines method.
Then I created 2 variables List(Of T) T stands for Type. Ours Types are Runner and School. I used List(Of T) instead of arrays because I don't have to worry about what the size of the list is. No ReDim Preserve, just keep adding items. The FillList method adds the data to the lists. First I had to find where the schools ended and the runners started. I used the Array.FindIndex method which is a bit different because the second parameter is a predicate. Check it out a bit. Now we know the indexes of the lines we want to use for each list and use a For...Next loop. In each loop an instance of the class is created and the properties set. Finally the new object is added to the the list.
Finally we fill the list boxes with a simple .AddRange and the lists.ToArray. Note that we are adding the entire object, properties and all. The neat thing is we can access the properties from the listbox items. Check out the SelectedIndexChanged event. You can do the same thing with the Runner list box.
Sorry, I couldn't just work with your code. I have all but forgotten the old vb6 methods. InStr, Mid etc. It is better when you can to use .net methods. It makes your code more portable when the boss says "Rewrite the whole application in C#"
Public Class Runner
Public Property BibNum As Integer
Public Property SchoolCode As String
Public Property FirstName As String
Public Property LastName As String
Public Overrides Function ToString() As String
'The listbox will call .ToString when we add a Runner object to determin what to display
Return $"{FirstName} {LastName}" 'or $"{LastName}, {FirstName}"
End Function
End Class
Public Class School
Public Property Code As String
Public Property Name As String
Public Property CoachFName As String
Public Property CoachLName As String
Public Property ADFName As String
Public Property ADLName As String
'The listbox will call .ToString when we add a School object to determin what to display
Public Overrides Function ToString() As String
Return Name
End Function
End Class
Private Runners As New List(Of Runner)
Private Schools As New List(Of School)
Private Function ReadData(path As String) As String()
Dim lines = File.ReadLines(path).ToArray
Return lines
End Function
Private Sub FillLists(data As String())
Dim location = Array.FindIndex(data, AddressOf FindRosterLine)
'The first line is the title so we don't start at zero
For index = 1 To location - 1
Dim SplitData = data(index).Split("|"c)
Dim Schl As New School
Schl.Code = SplitData(0)
Schl.Name = SplitData(1)
Schl.CoachFName = SplitData(2)
Schl.CoachLName = SplitData(3)
Schl.ADFName = SplitData(4)
Schl.ADLName = SplitData(5)
Schools.Add(Schl)
Next
For index = location + 1 To data.GetUpperBound(0)
Dim SplitData = data(index).Split("|"c)
Dim Run As New Runner
Run.BibNum = CInt(SplitData(0))
Run.SchoolCode = SplitData(1)
Run.FirstName = SplitData(2)
Run.LastName = SplitData(3)
Runners.Add(Run)
Next
End Sub
Private Function FindRosterLine(s As String) As Boolean
If s.Trim.StartsWith("# Roster") Then
Return True
Else
Return False
End If
End Function
Private Sub FillListBoxes()
Dim arrRunners As Runner() = Runners.ToArray
Dim arrSchools As School() = Schools.ToArray
ListBox1.Items.AddRange(arrSchools)
ListBox2.Items.AddRange(arrRunners)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim arrRunner = ReadData("Runners.txt")
FillLists(arrRunner)
FillListBoxes()
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
Dim Schl = DirectCast(ListBox1.SelectedItem, School)
TextBox1.Text = Schl.CoachLName
TextBox2.Text = Schl.Code
End Sub

String with apostrophe doubles when bound to property

I have a radgridview with a cell whose data may contain an apostrophe. When the row is selected, the row context is cast to a collection of public properties. This works well except for the cell with an apostrophe.
Private Sub dgSelectOrder_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
Dim row = TryCast(sender, GridViewRow)
Dim selectedOrder = TryCast(row.DataContext, myProperties)
If the cell data has an apostrophe, for example LET'S GO, the property returns the value LET''S GO. The apostrophe is doubled. If that data gets saved back to the database, then retrieved again, the property returns LET''''S GO.
How do I cast the row data correctly?
Public Class myProperties
Public Property pProjectNbr As String = String.Empty
Thanks.
I shouldn't have to do this but it's the only way it would work. I have similar code to cast the row.datacontext elsewhere. And that code runs as expected with the apostrophe.
Private Sub dgArchivedOrders_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
Dim row = TryCast(sender, GridViewRow)
Dim selectedOrder = TryCast(row.DataContext, myProperties)
If selectedOrder.pProjectNbr.Contains("''") Then
Dim convertThis As String = selectedOrder.pProjectNbr
selectedOrder.pProjectNbr = convertThis.Replace("''", "'")
End If

How to remove a record from a Listbox control in my WPF application with VB.Net code behind

I know similar questions to mine have been posted before, but I have tried various suggestions and nothing seem to work.
Here is my issue: I get the following error when trying to remove an item\from my listbox control:
Additional information: Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.
I need help removing an item from a listbox in WPF with VB.Net code-behind.
When I click a row in the listbox, I want to remove that item from the listbox.
I create alist of object 'ToLoadImages' to load into my listbox.
How would I remove the selected item from the list box and from my list ob object 'ToLoadImages'?
See my code below:
'CODE TO LOAD Listbox
Private Sub GetListToLoad(ClaimNo As String)
Dim ta As New ImagesDataSetTableAdapters.usp_SELECT_ImageTableAdapter
Dim dt As ImagesDataSet.usp_SELECT_ImageDataTable = ta.GetData(1, _ClaimNo, True)
Dim dr As DataRow
ListToLoad = New List(Of ToLoadImages)
Dim i As Integer = 0
For Each dr In dt
Dim ImgSource2() As Byte = DirectCast(dr(7), Byte())
Dim stream2 As MemoryStream = New MemoryStream
stream2.Write(ImgSource2, 0, ImgSource2.Length - 1)
stream2.Seek(0, SeekOrigin.Begin)
bitMap2 = New BitmapImage
bitMap2.BeginInit()
bitMap2.StreamSource = stream2
bitMap2.EndInit()
ListToLoad.Add(New ToLoadImages(dr(0), bitMap2))
Next
ImageListBox.ItemsSource = ListToLoad
End Sub
'Code to retrieve selected item from the listbox
'Here is where I want to add the code that will remove the selected item from my listbox and from the List of 'ToLoadImages'.
Private Sub ImageListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ImageListBox.SelectionChanged
Try
Dim itemsToLoad As ToLoadImages
itemsToLoad = ImageListBox.SelectedItem
Dim imageID as String = itemsToLoad.ImgID.ToString
Catch ex As Exception
MsgBox("Error encountered.")
End Try
End Sub
Class ToLoadImages
Public Class ToLoadImages
Private m_imgID As Integer
Private m_imageX As BitmapImage
Public Sub New(imgID As Integer, imagex As BitmapImage)
Me.m_imgID = imgID
Me.m_imageX = imagex
End Sub
Public Property ImgID() As Integer
Get
Return m_imgID
End Get
Set(ByVal value As Integer)
m_imgID = value
End Set
End Property
Public Property ImageX() As BitmapImage
Get
Return m_imageX
End Get
Set(ByVal value As BitmapImage)
m_imageX = value
End Set
End Property
End Class
Use ObservableCollection instead of List.
ObservableCollection
updates the changes automatically

Difficulty retrieving text in TextBox upon selecting an ID in ComboBox

Upon selecting a Question ID in the combo box the relating question should then appear in the text box. I am unsure how to get this to work though. I receive an error "Value of type......cannot be converted to string" on retrieveQuestion(). Any help is appreciated, thankyou.
Private Sub cmbQuestion_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbQuestion.SelectedIndexChanged
txtExistingQuestion.Text = retrieveQuestion() 'Add question, relevant to Question ID, to text box, DO I NEED .ToString?????????????????
loaded = True
End Sub
Public Function retrieveQuestion() As List(Of Question) 'Retrieves selected question into text box
Dim typeList As New List(Of Question)
Dim Str As String = "SELECT Question_ID, Question_Text FROM Question WHERE Question_ID =" & cmbQuestion.SelectedValue
Try
Using conn As New SqlClient.SqlConnection(DBConnection)
conn.Open()
Using cmdQuery As New SqlClient.SqlCommand(Str, conn)
Using drResult As SqlClient.SqlDataReader = cmdQuery.ExecuteReader()
While drResult.Read
typeList.Add(New Question(drResult("Question_ID"), drResult("Question_Text")))
End While
End Using 'Automatically closes connection
End Using
End Using
Catch ex As Exception
MsgBox("Question List Exception: " & ex.Message & vbNewLine & Str)
End Try
Return typeList
End Function
Public Class Question 'defining one club within class
Public Sub New(ByVal questionID As Integer, ByVal questionText As String)
mQuestionID = questionID 'm is for member of the class
mQuestionText = questionText
End Sub
Private mQuestionID As String = ""
Private mQuestionText As String = ""
Public Property QuestionID() As String
Get
Return mQuestionID
End Get
Set(ByVal value As String)
mQuestionID = value
End Set
End Property
Public Property QuestionText() As String
Get
Return mQuestionText
End Get
Set(ByVal value As String)
mQuestionText = value
End Set
End Property
End Class
Your issue is this line:
mQuestionID = questionID
In your class you have defined this:
Private mQuestionID As String = ""
But in your constructor, you are saying that questionID should be an Integer, like this:
Public Sub New(ByVal questionID As Integer, ByVal questionText As String)
You need to change your backing variable in your class (mQuestionID) to be an Integer, like this:
Private mQuestionID As Integer
This will also necessitate a change to the property syntax for QuestionID, like this:
Public Property QuestionID() As Integer
Get
Return mQuestionID
End Get
Set(ByVal value As Integer)
mQuestionID = value
End Set
End Property
Your error is originated by the return value of retrieveQuestion declared as a List(Of Question) but then you try to set the text property of a TextBox (and there is no way to convert automatically a List(Of Question) to a string)
So you could write something like this to extract the text of the first question in the list
Dim qList = retrieveQuestion()
if qList.Count > 0 then
txtExistingQuestion.Text = qList(0).QuestionText
loaded = True
End If
Of course, if your query returns zero or just one question, then there is no need to return a List(Of Question) and you can change the retrieveQuestion method to return just a Question or Nothing
Public Function retrieveQuestion() As Question
Dim questionResult As Question = Nothing
......
Using drResult As SqlClient.SqlDataReader = cmdQuery.ExecuteReader()
if drResult.Read() then
questionResult = New Question(drResult("Question_ID"), _
drResult("Question_Text")))
End if
End Using
....
return questionResult
End Function
Dim question = retrieveQuestion()
if question IsNot Nothing then
txtExistingQuestion.Text = question.QuestionText
loaded = True
End If
However, all the comments about string and integer conversion happening automatically on your code are really an alarm bell. You should strive to avoid this kind of conversion because they render your code weak and prone to misterious errors. Switch to Option Strinct On on your project properties and prepare yourself to a lot of conversion fixing.

Resources