Click here to Skip to main content
15,886,362 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I'm having trouble figuring out how to properly bind TextBoxes to a ComboBox that is populated with data from an XML file with the following structure:
XML
<?xml version="1.0" encoding="utf-8"?>
<CustDB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Customer>
    <Name />
    <Address1 />
    <Address2 />
    <Phone />
    <Fax />
    <Cell />
    <Other />
    <Attn />
    <Email />
    <SalesPerson />
  </Customer>
</CustDB>

My binding is done through LINQ to XML:
VB
Dim dbXML As String = "..\custdbTesting.xml"
        Dim contacts = XDocument.Load(dbXML, LoadOptions.PreserveWhitespace)
        Dim custQuery = From customer In contacts.Elements("CustDB").Elements("Customer") _
                        Order By customer.Value Ascending _
                        Select Nm = customer.Elements("Name").Value, Ad1 = customer.Elements("Address1").Value, Ad2 = customer.Elements("Address2").Value _
                        , Ph = customer.Elements("Phone").Value, Fx = customer.Elements("Fax").Value, Ce = customer.Elements("Cell").Value _
                        , Oth = customer.Elements("Other").Value, Atn = customer.Elements("Attn").Value, Eml = customer.Elements("Email").Value _
                        , SaPe = customer.Elements("SalesPerson").Value

        For Each result In custQuery
            cbxName.Items.Add(result.Nm)
        Next

XML
<ComboBox x:Name="cbxName"/>
<TextBox x:Name="txbAdd1" Margin="0,23,0,0" Text="{Binding SelectedItem, ElementName=cbxName}"/>

Can someone please help me figure out what I am doing wrong? I am using Visual Studio 2012 and adding binding through the TextBox properties docker. I assumed this would be straight forward, but not so.
Posted

Steps to do:
1) Create class:
VB
Public Class Customer

    Private sName As String = String.Empty
    Private sAddress1 As String = String.Empty
    Private sAddress2 As String = String.Empty
    Private sPhone As String = String.Empty
    Private sFax As String = String.Empty
    Private sCell As String = String.Empty
    Private sOther As String = String.Empty
    Private sAttn As String = String.Empty
    Private sEmail As String = String.Empty
    Private sSalesPerson As String = String.Empty

    Public Property CustName As String
        Get
            Return sName
        End Get
        Set(value As String)
            sName = value
        End Set
    End Property

    Public Property Address1 As String
        Get
            Return sAddress1
        End Get
        Set(value As String)
            sAddress1 = value
        End Set
    End Property

    Public Property Address2 As String
        Get
            Return sAddress2
        End Get
        Set(value As String)
            sAddress2 = value
        End Set
    End Property

    Public Property Phone As String
        Get
            Return sAddress2
        End Get
        Set(value As String)
            sAddress2 = value
        End Set
    End Property

    Public Property Fax As String
        Get
            Return sFax
        End Get
        Set(value As String)
            sFax = value
        End Set
    End Property

    Public Property Cell As String
        Get
            Return sCell
        End Get
        Set(value As String)
            sCell = value
        End Set
    End Property

    Public Property Other As String
        Get
            Return sOther
        End Get
        Set(value As String)
            sOther = value
        End Set
    End Property

    Public Property Attn As String
        Get
            Return sAttn
        End Get
        Set(value As String)
            sAttn = value
        End Set
    End Property

    Public Property Email As String
        Get
            Return sEmail
        End Get
        Set(value As String)
            sEmail = value
        End Set
    End Property

    Public Property SalesPerson As String
        Get
            Return sSalesPerson
        End Get
        Set(value As String)
            sSalesPerson = value
        End Set
    End Property


End Class

This class has the same members as your xml structure.

2) Create new Interface to be able to use class properties
VB
Public Interface ICustomer
    'properties
    Property Name As String
    Property Address1 As String
    Property Address2 As String
    Property Phone As String
    Property Fax As String
    Property Cell As String
    Property Other As String
    Property Attn As String
    Property Email As String
    Property SalesPerson As String

End

Read more about Interfaces[^]

3) Add new module. Define global variable Customers which holds the list of Customer. Create procedure/subroutine to load data from xml into Customers list.
VB
Module ModMain

    Public Customers As List(Of Customer) = Nothing

    Sub LoadXmlData(sFileName As String)
        Dim xDoc As XDocument = Nothing
        Dim custList As IEnumerable = Nothing
        Try

            Customers = New List(Of Customer)
            xDoc = XDocument.Load(sFileName, LoadOptions.PreserveWhitespace)
            custList = From customer In xdoc.Elements("CustDB").Elements("Customer") _
                            Order By customer.Value Ascending _
                            Select Nm = customer.Elements("Name").Value, Ad1 = customer.Elements("Address1").Value, Ad2 = customer.Elements("Address2").Value _
                            , Ph = customer.Elements("Phone").Value, Fx = customer.Elements("Fax").Value, Ce = customer.Elements("Cell").Value _
                            , Oth = customer.Elements("Other").Value, Atn = customer.Elements("Attn").Value, Eml = customer.Elements("Email").Value _
                            , SaPe = customer.Elements("SalesPerson").Value

            For Each c In custList
                Dim cu As Customer = New Customer
                With cu
                    .CustName = c.Nm
                    .Address1 = c.Ad1
                    .Address2 = c.Ad2
                    .Phone = c.Ph
                    .Fax = c.Fx
                    .Cell = c.Ce
                    .Other = c.Oth
                    .Attn = c.Atn
                    .Email = c.Eml
                    .SalesPerson = c.SaPe
                End With
                Customers.Add(cu)
            Next

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation, "Error...")

        Finally
            xDoc = Nothing
        End Try
    End Sub

End Module

See: IEnumerable Interface[^]

4) follow this link to find out how to create binding context.
Simple Data Binding in WPF[^] - step 2
XML
<TextBox Text="{Binding CustName}" Margin="10" Grid.Column="1"></TextBox>

More at CP KB:
A Very Simple Example of Data Binding in WPF[^]
WPF Data Binding - Part 1[^]

5) Finally, use this code:
VB
Class MainWindow
    ' on combobox selection change
    Private Sub CustCombo_SelectionChanged(sender As Object, e As SelectionChangedEventArgs)
        Try
            Dim cmb As ComboBox = sender
            Dim i As Integer = cmb.SelectedIndex
            Dim cust As Customer = Customers(i)
            Me.DataContext = cust

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation, "Error...")
        End Try
    End Sub

    'new instance of window/application
    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        'call LoadXmlData to fill global variable Customer as a List(of Customer)
        Dim sFileName As String = "D:\custdbTesting.xml"
        LoadXmlData(sFileName)
        'fill combobox with customer names
        For Each c As Customer In Customers
            Me.CustCombo.Items.Add(c.CustName)
        Next


    End Sub

End Class


Note: This is very basic sample. There's a lot to improve, for example: you can load data from xml to class via xml serialization[^].
A Complete Sample of Custom Class Collection Serialization and Deserialization[^]

Here you can download[^] a complete sample (without xml).

And the most important: i strongly recommend to read MSDN documentation[^].
 
Share this answer
 
v3
Comments
Sean Donnahoe 2-Dec-14 8:32am    
Thank you so much. This clarifies things immensely. I had been reading the MSDN Docs, but it was becoming more confusing. It really helped to see it laid out in the different modules, classes and interfaces. My dumb @$$ was trying to put everything in the MainWindow Class. I appreciate your help most sincerely. I'm sorry if I was a pain to deal with.
Maciej Los 2-Dec-14 8:41am    
You're very welcome. I'm glad i can help you.
Sean Donnahoe 2-Dec-14 11:24am    
A new issue has set in. When I click the Save Data button I have started a loop that checks if the user typed data exists in the Customers list. If not I want it to save the new entry in the XML, but every time I have tested it, it returns a value of both in the comparison to true signifying that the customer already exists.
<pre>
Private Sub btnSaveData_Click(sender As Object, e As RoutedEventArgs) Handles btnSaveData.Click
Try
'check if customer is already in DB
Dim CustExists As Boolean = False
For Each oldCust As Customer In Customers
If cbxName.Text = oldCust.CustName Then CustExists = True
Next

If CustExists = True Then MsgBox("Found: No need to create new customer")
'if not, then add the new info

'then SaveData()
Catch ex As Exception
MsgBox("Save data button error: " & ex.Message, MsgBoxStyle.Exclamation, "Error...")
End Try

End Sub
</pre>
The Boolean 'CustExists' always returns true. What am I doing wrong?

I have found that it only yields True if a previous list item has been selected.
Maciej Los 2-Dec-14 11:33am    
Imagine, that customers in Combobox comes from XML file. If you want add new one, please create new window to add it using:
c As Customer = new Customer. Then you should check if customer exists or not. You need to use global variable Customers! Customers.Contains(c), where c is newly_created_customer. Do not "filter" it via combobox!
Sean Donnahoe 2-Dec-14 13:05pm    
Awesome. Thanks!
Where do you call the data loading code?
I have copied all your code and it worked like a charm. Naturally I modified the file path, but I suppose that the path is OK for you, considering that an exception appear when you have wrong path.

By the way, is there any chance that by mistake you are referencing another custdbTesting.xml and not the one you want? It seems, that you read from a file that is in directory project directory/bin.

I call data loading, when the MainWindow is loaded:
<window x:class="MainWindow" xmlns:x="#unknown">
        ...
        Loaded="Window_Loaded_1">
...
<!-- UI element definitions -->
</window>

and the code behind:
Private Sub Window_Loaded_1(sender As Object, e As RoutedEventArgs)
        Dim dbXML As String = "../../custdbTesting.xml"
        ' File path to my test file in project folder
        ' Rest is the same you wrote
        ...
End Sub
 
Share this answer
 

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