0
votes

I am attempting to bind a ObservableCollection to a ListView but when I attempt to debug the program VS2010 is throwing the exception "Window must be the root of the tree. Cannot add Window as a child of Visual"

If I was to remove the attempted ItemsSource binding the WPF window opens (obviously without any data in the listView). I have create a Sub in my codebehind that parses an XML file and adds values to the ObservableCollection, I then bind the ListView.

I have stepped through the code, and the error appears to be in the XAML as the Sub completes without error, the program errors after the CodeBehind has completed, everytime.

My XAML file is as follows:

<Window x:Class="test_ListView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="test_ListView" Height="300" Width="300">
    <Grid>
        <ListView Height="105" HorizontalAlignment="Left" Name="lst_EmergencyContacts" VerticalAlignment="Top" Width="478">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" Width="160" />
                    <GridViewColumn DisplayMemberBinding="{Binding emContactsNumber}" Header="Number" Width="70" />
                    <GridViewColumn DisplayMemberBinding="{Binding emContactsPhoneCoverage}" Header="Phone Coverage" Width="95" />
                    <GridViewColumn DisplayMemberBinding="{Binding distListPhone}" Header="Distance" Width="60" />
                    <GridViewColumn Header="More" Width="60" />
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

While I believe the error is within the XAML, I will include the CodeBehind details, just in case (as the program will run without the error if the Sub isnt called that binds the ListView).

    Public Property emContactsName() As String
        Get
            Return em_Name
        End Get
        Set(ByVal value As String)
            em_Name = value
        End Set
    End Property
    Private em_Name As String
    Public Property emContactsNumber() As String
        Get
            Return em_Number
        End Get
        Set(ByVal value As String)
            em_Number = value
        End Set
    End Property
    Private em_Number As String
    Public Property emContacts27Mhz() As String
        Get
            Return em_27Mhz
        End Get
        Set(ByVal value As String)
            em_27Mhz = value
        End Set
    End Property
    Private em_27Mhz As String
    Public Property emContactsUhf() As String
        Get
            Return em_Uhf
        End Get
        Set(ByVal value As String)
            em_Uhf = value
        End Set
    End Property
    Private em_Uhf As String
    Public Property emContactsVhf() As String
        Get
            Return em_Vhf
        End Get
        Set(ByVal value As String)
            em_Vhf = value
        End Set
    End Property
    Private em_Vhf As String
    Public Property IsSelected() As Boolean
        Get
            Return m_IsSelected
        End Get
        Set(ByVal value As Boolean)
            m_IsSelected = value
        End Set
    End Property
    Private m_IsSelected As Boolean
    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        getEmergencyContactsData("\", "EmergencyContacts.xml")
    End Sub

Private Sub getEmergencyContactsData(ByVal docPath As String, ByVal docName As String)
        Try
            Dim xDoc As XmlDocument = New XmlDocument
            Dim nList As XmlNodeList
            Dim node As XmlNode
            xDoc.Load(docPath + docName)
            nList = xDoc.SelectNodes("/items/item")
            Dim emergencyContactsCollection As New ObservableCollection(Of test_googleLookup)()
            For Each node In nList
                Dim eID = node.Attributes.GetNamedItem("id").Value
                Dim eName = node.ChildNodes.Item(0).InnerText
                Dim eNumber = node.ChildNodes.Item(1).InnerText
                Dim eRadio27Mhz = node.ChildNodes.Item(2).InnerText
                Dim eRadioUhf = node.ChildNodes.Item(3).InnerText
                Dim eRadioVhf = node.ChildNodes.Item(4).InnerText
                emergencyContactsCollection.Add(New test_googleLookup() With {.emContactsName = eName, .emContactsNumber = eNumber, .emContacts27Mhz = eRadio27Mhz, .emContactsUhf = eRadioUhf, .emContactsVhf = eRadioVhf, .IsSelected = 0})
            Next
            ' Add to resources
            Resources("emergencyContactsCollection") = emergencyContactsCollection
            lst_EmergencyContacts.ItemsSource = emergencyContactsCollection
        Catch
        End Try
    End Sub

I can see when stepping through the debug that the XML file is being correctly parsed and the values being added to the ObservableCollection.

If anyone can provide any assistance it would be greatly appreciated.

Thanks.

2

2 Answers

1
votes

Try changing emergencyContactsCollection into a public property (ie.,EmergencyContacts) of test_ListView. Set the DataContext of lst_EmergencyContacts to be EmergencyContactsCollection.

<Window x:Class="test_ListView" ... DataContext="{Binding RelativeSource={RelativeSource Self}}">

<ListView Name="lst_EmergencyContacts" ... DataContext="{Binding Path=EmergencyContacts}">

Managing your data binding in this way often makes things much easier. Even better would be to separate out the data bound Properties to their own ViewModel.

0
votes

I ended up using ListBoxes, below is the code I used, in case anyone is interested:

<ListBox Grid.Row="1" Grid.Column="0" Grid.RowSpan="4" Grid.ColumnSpan="3" HorizontalAlignment="Stretch"  ItemsSource="{DynamicResource emergencyContactsCollection}" Name="lst_emergencyServices" VerticalAlignment="Stretch">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <CheckBox IsChecked="{Binding emerContIsSelected, Mode=TwoWay}" />
                                    <TextBlock Text="{Binding emerContName}" />
                                    <TextBlock Text="{Binding emerContNumber}" />
                                    <TextBlock Text="{Binding emerContRadio27mhz}" />
                                    <TextBlock Text="{Binding emerContRadioUhf}" />
                                    <TextBlock Text="{Binding emerContRadioVhf}" />
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>

Thank you for your time and assistance.

Matt