Click here to Skip to main content
15,881,044 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Please keep in mind while reading this, I am using vb.net 4.0 to write a wpf user control. I have an ASCII text file that contains tab delimited customer contact info (herein refered to as DB)...
<vbTab> Customer Name <vbTab> Address 1 <vbTab> Address 2 <vbTab> Phone <vbTab> Fax <vbTab> Cell <vbTab> OtherPhone <vbTab> Contact <vbTab> email

All in all there are 9 fields, some may be blank within the DB.
I need to read each line into an array splitting each line at vbNewLine,
then each line to an array splitting at vbTab.

I will be using this array to populate a Combobox with the Customer Name field in the array and 8 other TextBox controls with the corresponding fields.

When the ComboBox changes I want the other 8 TextBoxes to update accordingly.

Finally, when the ComboBox is manually changed to a value that is not present in the original DB, or if any contact info is changed for a customer, I want to add the new or revised record to the DB. I also want to sort the DB by customer name.
I know this is asking a lot at once, but I had this working in VBA 6.0 and am trying to convert to .Net 4.0
Would it be helpful to post the original VBA code?
Posted
Updated 27-Feb-13 5:47am
v2
Comments
[no name] 27-Feb-13 11:55am    
I do not know if posting the VBA code would help or not as your question is not clear at all. Read the text out of the file and use the Split method to separate your fields. What is the problem that you are having?
Sean Donnahoe 27-Feb-13 12:58pm    
The problem I am having, is wrapping my head around arrays. My original macro code is quite lengthy (I suspect from the lack of array processing options in VBA6).

I want to know how to populate the textboxes by calling the index value from the combobox change.
[no name] 27-Feb-13 13:14pm    
textbox.Text = yourArray(index) should do it for you. At least I think that is what you are asking. it would help if you posted the .NET code you have written and described the problem or what it is that is not working.

Were you using a Structure in VB6? Anyhow .Net is very different. You should read some articles about .Net before you attempt to just port VB6 code directly into .Net.

There are many ways to accomplish parsing a delimited file. Below is a simple example of code that will work:

VB
Using fs As StreamReader = File.OpenText("C:\File.txt")
   While fs.Peek() <> -1
	Dim line As String = fs.ReadLine()
	Dim fields As String() = line.Split(New String() {"/t"}, StringSplitOptions.None)
	'Do more stuff like add it to a DataTable, array or generic list
   End While
End Using
 
Share this answer
 
v7
Comments
Sean Donnahoe 27-Feb-13 13:05pm    
Unfortunately, since I am using .Net 4.0, I can't use StreamReader or any My. functionality. Those are only available in .Net 4.5
[no name] 27-Feb-13 13:15pm    
StreamReader IS available in versions < 4.5. Where did you get that idea?
Sean Donnahoe 27-Feb-13 14:24pm    
because it isn't available to me when I try to input the code (see screen shot)...
oatesflag.com/images/temp/vb_error.jpg
[no name] 27-Feb-13 14:53pm    
Are you importing System.IO?
Sean Donnahoe 27-Feb-13 14:58pm    
no, my current imports are...
Imports c = Corel.Interop.CorelDRAW
Imports v = Corel.Interop.VGCore
I assume that i should add
Imports sio = System.IO
You can use File.ReadAllText() to read teh file and the .Split method will turn the string into an array.

Arrays have a sort method.


If you can just re-write the file when something is added to the array, I believe the file.writealltext would work for the output.
 
Share this answer
 
Sean,

Relax it is not that hard. They made VB.Net very friendly to VB6 programmers.

Some might argue to friendly to the point that it causes confusion, but that discussion will not help you.

The reason you are not seeing the StreamReader class is that you have not imported the necessary namespace. VB imports several for you automatically behind the scenes, but the one that you need is System.IO. System.IO is in one of the default assemblies loaded for you, but it is not automatically imported.

To see which assemblies and namespaces are loaded for your project, go the Project Menu and select "YourAssemblyName Properties"; if you did not set a name when you created the project, this most likely will be name "WindowsApplication1 Properties". You should now be on the Application tab of the properties page. Select the References tab to see all the assemblies loaded for your project. On the bottom of that tab you will see the default namespaces imported from those assemblies. Anything with a check-mark is automatically available. At this point you could scroll down to System.IO and check that one, or you code go back to your code and add this statement at the top of the code.

Imports System.IO

Remember that this just provides you a short cut to specifying what class you want to use. You could just as well type this:

Dim sr As New System.IO.StreamReader

If using the StreamReader is a bit overwhelming for you at this point, VB provides a helper class for reading delimited files called TextFieldParser[^]. In that example, you would need the set the delimiter to VbTab (see a familiar constant) instead of the comma shown.

Once you have your arrays read in, you can set the ComboBox's DataSource property equal to the needed array. In this example, I have used a list of string arrays as a central storage device.

Public Class Form1

    ' combosource could hold your string arrays
    Dim combosource As New List(Of String())

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        ' simulate reading your data
        ' adding string arrays to combosource
        combosource.Add({"1", "2"})
        combosource.Add({"4", "42"})

        ' Note the zero based indexing here
        ComboBox1.DataSource = combosource(0)
        ComboBox2.DataSource = combosource(1)
    End Sub
End Class
 
Share this answer
 
Comments
Sean Donnahoe 27-Feb-13 16:42pm    
I got the code working thus far (see below), but I'm kinda confused at this point. I could do
Combobox.Items.Add(fields(1))
to populate the combobox, but how do I relate the other changes to the textboexs? I'm getting confused about Multidimensional arrays.

Dim path As String = "C:\Users\sean\Dropbox\Visual Studio 2012\Projects\SD_DataBaseTest\SD_DataBaseTest\CustDB.txt"
Dim str As String = "Fields..."
Dim sr As StreamReader = New StreamReader(path)
Do While sr.Peek() >= 0
'MessageBox.Show(sr.ReadLine())
Dim records As String = sr.ReadLine()
MessageBox.Show("Records: " & records)
Dim fields As String() = records.Split(New String() {vbTab}, StringSplitOptions.None)
For i As Integer = 0 To fields.GetUpperBound(0)
str = str & vbLf & i & ": " & fields(i)
Next
MessageBox.Show(str)
str = ""
Loop
Sean,

I just realized that I did not read your original post accurately. This is my understanding at this point.
1. You are reading in multiple records from your text file
2. One of the Fields in the record is "Name".
3. You want to populate a combobox with the name fields.
4. The textboxes should auto update with based on the combobox value.
5. This is a WPF usercontrol.

I only put the combobox and 2 textboxes on the UC, but you should get the idea. The code behind the UC will need to be adjusted to match your data. It reads your DB into a DataTable and uses binding to handle the rest.

Edit Modified to address comments:

Imports System.IO
Imports System.Data

Partial Public Class UserControl1
   Private Dt As New System.Data.DataTable
   Private source As New Binding

   Private fn As String = "d:\my documents\fields.txt"


   Private Sub UserControl1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
      Dim r As System.Data.DataRow
      With Dt
         .Columns.Add("FX", GetType(String)) 'added this for you preceeding tab
         .Columns.Add("Name", GetType(String))
         .Columns.Add("F1", GetType(String)) ' replace F# with something more meaningful
         .Columns.Add("F2", GetType(String))
         .Columns.Add("F3", GetType(String))
         .Columns.Add("F4", GetType(String))
         .Columns.Add("F5", GetType(String))
         .Columns.Add("F6", GetType(String))
         .Columns.Add("F7", GetType(String))
         .Columns.Add("F8", GetType(String))
         .DefaultView.Sort = "[Name] ASC"

         Dim sr As New IO.StreamReader(fn)

         Do While sr.Peek() <> -1
            r = .NewRow
            r.ItemArray = sr.ReadLine().Split(New Char() {vbTab(0)}, 9, System.StringSplitOptions.None)
            .Rows.Add(r)
         Loop
         sr.Close()
      End With

      ComboBox1.DataContext = Dt
      TextBox1.DataContext = Dt
      TextBox2.DataContext = Dt
   End Sub


   ' this is the method to write out the datatable
   Public Sub WriteDB()
      Dim sw As IO.StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(fn, False)
      Dim line As New System.Text.StringBuilder(1000)
      For Each r As DataRow In Dt.Rows
         line.Length = 0
         For Each obj As Object In r.ItemArray

            If obj IsNot DBNull.Value AndAlso Not String.IsNullOrEmpty(obj.ToString) Then

               line.Append(obj.ToString)

            End If
            line.Append(vbTab)
         Next
         sw.WriteLine(line.ToString)
      Next
      sw.Close()
   End Sub

   Private Sub ComboBox1_GotFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ComboBox1.GotFocus
      Dt.DefaultView.RowFilter = Filter()
      ComboBox1.EditableTextBox.CaretIndex = ComboBox1.Text.Length
      ComboBox1.EditableTextBox.SelectionLength = 0
      ComboBox1.IsDropDownOpen = True
      ComboBox1.StaysOpenOnEdit = True
   End Sub

   Private Function Filter() As String
      Return "[Name] Like '" & ComboBox1.Text & "*'"
   End Function

   Private Sub ComboBox1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Input.KeyEventArgs) Handles ComboBox1.KeyUp
      Dim tmp As String = ComboBox1.Text
      Dt.DefaultView.RowFilter = Filter() ' "[Name] Like '" & ComboBox1.Text & "*'"

      ComboBox1.SelectedIndex = -1
      ComboBox1.Text = tmp
      ComboBox1.EditableTextBox.CaretIndex = ComboBox1.Text.Length

   End Sub

   Private Sub ComboBox1_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ComboBox1.LostFocus
      ComboBox1.IsDropDownOpen = False
      ' ****** Hack.  
      ' There must be a better way to force this update, if Name is not in the data
      Dim tmp As String = ComboBox1.Text
      ComboBox1.Text = ""
      ComboBox1.Text = tmp
      ' ***** End Hack
   End Sub

End Class

' created a custom combobox so that I could access the internal textbox
Public Class myCombo
   Inherits System.Windows.Controls.ComboBox

   Friend ReadOnly Property EditableTextBox() As TextBox
      Get
         Return (TryCast(MyBase.GetTemplateChild("PART_EditableTextBox"), TextBox))
      End Get
   End Property
End Class



<UserControl x:Class="UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="269" Height="263"
    xmlns:MyNamespace="clr-namespace:WpfApplication1"    
>
    
    <Grid Height="122" Width="200">
        
        <MyNamespace:myCombo 
                  Height="23" HorizontalAlignment="Left" Margin="5,0,0,0" x:Name="ComboBox1" 
                  VerticalAlignment="Top" Width="150" IsSynchronizedWithCurrentItem="True"
                  IsEditable="True" 

                  IsTextSearchEnabled="False"
                  
                  ItemsSource="{Binding}"
                  DisplayMemberPath="Name"            
        />
        

        <TextBox Margin="5,51,45,48" Name="TextBox1" Text="{Binding Path=F1}"/>
        
        <TextBox Margin="5,0,0,13.5"  Height="20" Name="TextBox2" Text="{Binding Path=F2}" 
                 VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="150" />
    </Grid>
</UserControl>
 
Share this answer
 
v2
Comments
Sean Donnahoe 28-Feb-13 9:35am    
Thanks TnTinMn your code works great [with a few typo tweaks :)]. However, there is a small catch, my DB file has a leading VBTab on each row, which puts all the data off by one position. I added a new column at the top of the Dt structure, which seems to have fixed this, but now ComboBox1 only shows "System.Data.DataRowView" as it's contents. The drop down area shows all the names and the rest of the text boxes update as expected, but the upper contents of ComboBox1 never visually change.
I have 2 scenarios at this point.
After I change ComboBox1 to IsEditable...
1. When I change the contents of ComboBox1 manually I want to test the data table to see if there is an entry that matches and update the text boxes accordingly.
2. If I manually change the contents of one of the text boxes, I want the new data updated in the table and written back to the CustDB.txt file. I have a button on my form that is intended to write data to the ASCII text file, but I haven't coded it yet.
TnTinMn 28-Feb-13 21:29pm    
I was bored so I thought I would give it a try. I'm still new to WPF.
Besides, I found many comments that doing a filtered ComboBox was pain and I like a challenge. :)

I replaced the code in my previous post to give what I think you are looking for. I now agree with a comment that I found that WPF can hurt your brain, :)) WinForms is so much easier to to achieve this with. At least I didn't give you a WinForm control and tell you to host it in WPF.
Sean Donnahoe 1-Mar-13 13:30pm    
TnTinMn, I have been putting your code into my project and I ran across a problem.
Dim sw As IO.StreamWriter = My....
doesn't have .Computer. I only get options for ".MySettings" ".Resources" & ".Settings"
Any ideas what to do?
Sean Donnahoe 1-Mar-13 14:14pm    
Also, the line xmlns:MyNamespace="clr-namespace:WpfApplication1" in the top of the XAML is throwing an error.
Error 4 Undefined CLR namespace. The 'clr-namespace' URI refers to a namespace 'WpfApplication1' that could not be found. C:\Users\sean\Dropbox\Visual Studio 2012\Projects\OrderForms_4.5\OrderForms_4.5\Docker.xaml 7 32 OrderForms_4.5

Even after I changes "WpfApplication1" to "Docker"
TnTinMn 1-Mar-13 15:29pm    
Go to the Project Properties page. On the Application Tab Copy the RootNamespace field and substitute that for WpfApplication1. You may have to issue a rebuild to get it to take. I had a few isssues also when I typed it in as well. Since it looks like you are using VS2012, it looks like they still have not made it any friendlier to use than it is in VS2008.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900