Treeview With One To Many Linq to SQL tables - wpf

I have a couple tables dealing with cars:
<Table(Name:="tblManufacturer")> Public Class dbManufacturers
Private _ManufacturerID As Integer
<Column(Storage:="_ManufacturerID", DbType:="int IDENTITY NOT NULL", IsPrimaryKey:=True, IsDbGenerated:=True, Name:="ManufacturerID")> _
Public Property ManufacturerID() As Integer
Get
Return Me._ManufacturerID
End Get
Set(value As Integer)
Me._ManufacturerID = value
End Set
End Property
Private _ManufacturerName As String
<Column(Storage:="_ManufacturerName", DbType:="Varchar(50)", Name:="ManufacturerName")> _
Public Property ManufacturerName() As String
Get
Return Me._ManufacturerName
End Get
Set(value As String)
Me._ManufacturerName = value
End Set
End Property
Private _Models As EntitySet(Of dbModels) = New EntitySet(Of dbModels)
<Association(Storage:="_Models", DeleteRule:="CASCADE", OtherKey:="ManufacturerID")> _
Public Property Models As EntitySet(Of dbModels)
Get
Return _Models
End Get
Set(value As EntitySet(Of dbModels))
_Models.Assign(value)
End Set
End Property
End Class
<Table(Name:="tblModels")> Public Class dbModels
Private _ModelID As Integer
<Column(Storage:="_ModelID", DbType:="int IDENTITY NOT NULL", IsPrimaryKey:=True, IsDbGenerated:=True, Name:="ModelID")> _
Public Property ModelID() As Integer
Get
Return Me._ModelID
End Get
Set(value As Integer)
Me._ModelID = value
End Set
End Property
Private _ManufacturerID As Integer
<Column(Storage:="_ManufacturerID", DbType:="int", Name:="ManufacturerID")> _
Public Property ManufacturerID() As Integer
Get
Return Me._ManufacturerID
End Get
Set(value As Integer)
Me._ManufacturerID = value
End Set
End Property
Private _ModelName As String
<Column(Storage:="_ModelName", DbType:="Varchar(200)", Name:="ModelName")> _
Public Property ModelName() As String
Get
Return Me._ModelName
End Get
Set(value As String)
Me._ModelName = value
End Set
End Property
End Class
The XAML:
<TreeView Name="TreeView1" Margin="3" ItemsSource="{Binding ElementName=ManufacturerInfo, Path=tblManufacturers}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate>
<TextBlock Text="{Binding Path=ManufacturerName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Source=Models, Path=ModelName}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
The code behind:
Public Class ManufacturerInfo
Private LinqDB As New DataContext(My.Settings.dbConnection)
Property tblManufacturers As Table(Of dbManufacturers) = LinqDB.GetTable(Of dbManufacturers)()
Public Sub New()
InitializeComponent()
End Sub
Private Sub ManufacturerInfo_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Me.DataContext = Me
End Sub
End Class
So I get the list of Manufacturers, but not the nested models. Is there a way to make this work, or do I have to change how I'm doing my LINQ query?
I'm having trouble finding similar treeview examples.

Figured it out.
Still have a bit to learn about the subtle art of data binding.
<TreeView Name="TreeView1" Margin="3" ItemsSource="{Binding ElementName=ManufacturerInfo, Path=tblManufacturers}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Models}">
<TextBlock Text="{Binding Path=ManufacturerName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ModelName}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Related

Access to TextBoxes in all ListView rows - WPF - VB.NET

How can I access to TextBoxes in all ListView rows? I have also tried the two-way method, but it is only one-way.
<ListView Name="ListViewParameters" >
<ListView.View>
<GridView>
<GridViewColumn Header="Value" Width="120" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="TextWidth" Text="{Binding Path=Width, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
...
.
Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
ListViewParameters.ItemsSource = Parameters
End Sub
.
Public Structure Parameter
Private _width As Integer
Private _length As Integer
Private _height As Integer
Property Width() As Integer
Get
Return _width
End Get
Set(Value As Integer)
_width = Value
End Set
End Property
Property Length() As Integer
Get
Return _length
End Get
Set(Value As Integer)
_length = Value
End Set
End Property
Property Height() As Integer
Get
Return _height
End Get
Set(Value As Integer)
_height = Value
End Set
End Property
End Structure
Public ReadOnly Parameters As New ObservableCollection(Of Parameter)
My goal is to calculate the volume:
Private Sub ButtonCalculate_Click(sender As Object, e As RoutedEventArgs)
Dim volume As Integer = 1
For Each t As TextBox In ListParameters
volume *= CInt(t.Text)
Next
MsgBox(volume.ToString)
End Sub
(This is for learning only)

WPF VB.Net Datagrid Value from a specific Cell in FullRow Selection Mode?

How can I get a Value from a specific Cell in a Datagrid with the Selection Mode FullRow ?
At the moment I use this command, but it only display's the Value if I manually select the cell:
Public Sub MenuItem_Click(sender As Object, e As RoutedEventArgs)
Dim selectedData As String = ""
Dim wert As String = ""
For Each dataGridCellInfo In myGridView.SelectedCells()
Dim pi As Reflection.PropertyInfo = dataGridCellInfo.Item.[GetType]().GetProperty(dataGridCellInfo.Column.Header.ToString())
Dim value = pi.GetValue(dataGridCellInfo.Item, Nothing)
selectedData += dataGridCellInfo.Column.Header + ": " + value.ToString() + vbLf
wert = value.ToString
Next
MessageBox.Show(selectedData)
End Sub
But I don't want to manually select the cell all time.
I just want to click on any cell in that Row and get always the value from the cell "Pfad" and put it in a String.
XAML DataGrid Code:
<DataGrid Name="myGridView" SelectionUnit="Cell" IsReadOnly="True" ItemsSource="{Binding}" Grid.ColumnSpan="3" Background="#FFA4A4A4" BorderThickness="2" BorderBrush="#FF6A6F77" AutoGenerateColumns="False" Margin="10,31,10,149.714" GridLinesVisibility="None">
<DataGrid.Columns>
<DataGridTextColumn Header="Track" Binding="{Binding Path=Track}" Width="100"/>
<DataGridTemplateColumn Header="">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Width="50" Height="50" VerticalAlignment="Center" HorizontalAlignment="Center" Source="{Binding Path=Image}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding Path=Endung}" Width="100" Header=" Container"/>
<DataGridTextColumn Binding="{Binding Path=Album}" Width="100" Header="Album"/>
<DataGridTextColumn Binding="{Binding Path=Bitrate}" Width="100" Header="Bitrate"/>
<DataGridTextColumn Binding="{Binding Path=Pfad}" Width="100" Header="Pfad"/>
</DataGrid.Columns>
</DataGrid>
Code-Behind:
Public Structure Austauscher
Dim files As New ObservableCollection(Of Austauscher)
Private _track As String
Private _image As BitmapImage
Private _album As String
Private _pfad As String
Private _bitrate As String
Private _endung As String
Property Track() As String
Get
Return _track
End Get
Set(ByVal Value As String)
_track = Value
End Set
End Property
Property Image As BitmapImage
Get
Return _image
End Get
Set(ByVal Value As BitmapImage)
_image = Value
End Set
End Property
Property Album() As String
Get
Return _album
End Get
Set(ByVal Value As String)
_album = Value
End Set
End Property
Public Property Pfad As String
Get
Return _pfad
End Get
Set(ByVal Value As String)
_pfad = Value
End Set
End Property
Property Bitrate As String
Get
Return _bitrate
End Get
Set(ByVal Value As String)
_bitrate = Value
End Set
End Property
Property Endung As String
Get
Return _endung
End Get
Set(ByVal Value As String)
_endung = Value
End Set
End Property
End Structure
At first you need tu open de event "CellClick" on your datagridview and put de following code:
If (e.ColumnIndex <> -1) And (e.RowIndex <> -1) Then
Dim selectedCell as string = ""
selectedCell = myGridView.rows(e.rowIndex).cells("numberOfCell").valeu
End If
If this Answer has help you. Pleas mark this at the correct Answer.

WPF Parent Element Lost Focus

I am developing a WPF application. In one of my pages I have a DockPanel with 3 ComboBoxes within it. These 3 ComboBoxes are dependent on each other. So, I have a binding group on the DockPanel and a validation rule for that binding group.
I would like to validate these 3 ComboBoxes when the DockPanel loses focus; however, the DockPanel's LostFocus event is fired when the user clicks on one of the child ComboBoxes within it!
I would have thought that if the child control has focus, the parent control would also have focus...however this does not seem to be the case.
I am looking for a solution to perform validation on the binding group when the DockPanel loses focus...where the focus is lost to a control that is not one of its children.
Edit:
So, I created as simple an application as I could to demonstrate the problem.
I have a "FertilizerCombination" class that contains 3 integers that make up the Fertilizer. These must be unique within the application. Currently the only combination that is not available is 10-10-10. This is a hard coded value in the class.
Public Class FertilizerCombination
Private _nitrogen As Integer
Private _phosphorous As Integer
Private _potassium As Integer
<System.ComponentModel.DataAnnotations.Range(1, 20)> _
Public Property Nitrogen As Integer
Get
Return _nitrogen
End Get
Set(value As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, NitrogenValidationContext)
_nitrogen = value
End Set
End Property
<System.ComponentModel.DataAnnotations.Range(1, 20)> _
Public Property Phosphorous As Integer
Get
Return _phosphorous
End Get
Set(value As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, PhosphorousValidationContext)
_phosphorous = value
End Set
End Property
<System.ComponentModel.DataAnnotations.Range(1, 20)> _
Public Property Potassium As Integer
Get
Return _potassium
End Get
Set(value As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, PotassiumValidationContext)
_potassium = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(ByVal nitrogen As Integer, ByVal phosphorous As Integer, ByVal potassium As Integer)
Me.Nitrogen = nitrogen
Me.Phosphorous = phosphorous
Me.Potassium = potassium
End Sub
Public Shared Function FertilizerCombinationAvailable(ByVal nitrogen As Integer, ByVal phosphorous As Integer, ByVal potassium As Integer) As Boolean
'Checking against combinations already used'
If nitrogen = "10" And phosphorous = "10" And potassium = "10" Then
'Combination has already been used'
Return False
End If
'Combination was not used yet'
Return True
End Function
Public Sub SetFertilizerCombination(ByVal nitrogen As Integer, ByVal phosphorous As Integer, ByVal potassium As Integer)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(nitrogen, NitrogenValidationContext)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(phosphorous, PhosphorousValidationContext)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(potassium, PotassiumValidationContext)
If FertilizerCombination.FertilizerCombinationAvailable(nitrogen, phosphorous, potassium) = False Then
Throw New ArgumentException("This fertilizer combination has already been used")
End If
Me.Nitrogen = nitrogen
Me.Phosphorous = phosphorous
Me.Potassium = potassium
End Sub
Private NitrogenValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Nitrogen"}
Private PhosphorousValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Phosphorous"}
Private PotassiumValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Potassium"}
End Class
I have a created a Validation Rule for the Fertilizer Combination Class:
Public Class FertilizerCombinationValidationRule
Inherits ValidationRule
Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As System.Globalization.CultureInfo) As System.Windows.Controls.ValidationResult
Dim bg As BindingGroup = TryCast(value, BindingGroup)
If bg IsNot Nothing AndAlso bg.Items.Count > 0 Then
'The BindingGroup Items property contains the original object(s)'
Dim fertilizerCombo As FertilizerCombination = TryCast(bg.Items(0), FertilizerCombination)
'Using the BindingGroups GetValue method to retrieve the user provided values'
Dim proposedNitrogen As Integer
Dim proposedPhosphorous As Integer
Dim proposedPotassium As Integer
Try
proposedNitrogen = bg.GetValue(fertilizerCombo, "Nitrogen")
proposedPhosphorous = bg.GetValue(fertilizerCombo, "Phosphorous")
proposedPotassium = bg.GetValue(fertilizerCombo, "Potassium")
If FertilizerCombination.FertilizerCombinationAvailable(proposedNitrogen, proposedPhosphorous, proposedPotassium) = False Then
Return New ValidationResult(False, "This fertializer combination has already been used")
End If
Catch noValue As System.Windows.Data.ValueUnavailableException
'a binding was not properly bound yet'
End Try
End If
Return New ValidationResult(True, Nothing)
End Function
End Class
I have a "PlantSolution" class that has a FertilizerCombination property. I also have a VM for that class so that it's easy for binding in the XAML:
Public Class PlantSolutionVM
Public Property PlantSolution As PlantSolution
Public Sub New()
PlantSolution = New PlantSolution("Produce Blooms", "Using this fertilizer will help your plant produce flowers!", 10, 10, 20)
End Sub
End Class
Public Class PlantSolution
Private _name As String
Private _description As String
Private _fertilizer As FertilizerCombination
<System.ComponentModel.DataAnnotations.Required()>
Public Property Name As String
Get
Return _name
End Get
Set(value As String)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, NameValidationContext)
_name = value
End Set
End Property
<System.ComponentModel.DataAnnotations.Required()>
Public Property Description As String
Get
Return _description
End Get
Set(value As String)
System.ComponentModel.DataAnnotations.Validator.ValidateProperty(value, DescriptionValidationContext)
_description = value
End Set
End Property
Public ReadOnly Property Fertilizer As FertilizerCombination
Get
Return _fertilizer
End Get
End Property
Public Sub New(name As String, description As String, nitrogen As Integer, phosphorous As Integer, potassium As Integer)
_fertilizer = New FertilizerCombination(nitrogen, phosphorous, potassium)
Me.Name = name
Me.Description = description
End Sub
Private NameValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Name"}
Private DescriptionValidationContext = New System.ComponentModel.DataAnnotations.ValidationContext(Me, Nothing, Nothing) With {.MemberName = "Description"}
End Class
Now here is my XAML for a window called "FunWithFocus":
<Grid>
<Grid.Resources>
<x:Array x:Key="CombinationOptions" Type="sys:Int32" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:Int32>0</sys:Int32>
<sys:Int32>1</sys:Int32>
<sys:Int32>2</sys:Int32>
<sys:Int32>3</sys:Int32>
<sys:Int32>4</sys:Int32>
<sys:Int32>5</sys:Int32>
<sys:Int32>6</sys:Int32>
<sys:Int32>7</sys:Int32>
<sys:Int32>8</sys:Int32>
<sys:Int32>9</sys:Int32>
<sys:Int32>10</sys:Int32>
<sys:Int32>11</sys:Int32>
<sys:Int32>12</sys:Int32>
<sys:Int32>13</sys:Int32>
<sys:Int32>14</sys:Int32>
<sys:Int32>15</sys:Int32>
<sys:Int32>16</sys:Int32>
<sys:Int32>17</sys:Int32>
<sys:Int32>18</sys:Int32>
<sys:Int32>19</sys:Int32>
<sys:Int32>20</sys:Int32>
</x:Array>
<local:PlantSolutionVM x:Key="PlantSolutionVM" />
<Style TargetType="DockPanel">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid DataContext="{Binding Source={StaticResource PlantSolutionVM}, Path=PlantSolution}" Margin="50">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Solution Name:" Grid.Row="0" Grid.Column="0" Margin="5"/>
<TextBox x:Name="ItemName" Text="{Binding Name, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" Margin="5"/>
<TextBlock Text="Description of Problem:" Grid.Row="1" Grid.Column="0" Margin="5"/>
<TextBox x:Name="ItemDescription" Text="{Binding Description, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Grid.Row="1" Grid.Column="1" Margin="5"/>
<TextBlock Text="Recommended Fertilizer:" Grid.Row="2" Grid.Column="0" Margin="5"/>
<DockPanel x:Name="FertilizerCombinationContainer" DataContext="{Binding Fertilizer}" Grid.Row="2" Grid.Column="1" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top">
<DockPanel.BindingGroup>
<BindingGroup NotifyOnValidationError="True">
<BindingGroup.ValidationRules>
<local:FertilizerCombinationValidationRule />
</BindingGroup.ValidationRules>
</BindingGroup>
</DockPanel.BindingGroup>
<ComboBox x:Name="NitrogenValue" HorizontalAlignment="Left" VerticalAlignment="Top"
ItemsSource="{StaticResource CombinationOptions}"
SelectedItem="{Binding Nitrogen}"/>
<ComboBox x:Name="PhosphorousValue" HorizontalAlignment="Left" VerticalAlignment="Top"
ItemsSource="{StaticResource CombinationOptions}"
SelectedItem="{Binding Phosphorous}"/>
<ComboBox x:Name="PotatssiumValue" HorizontalAlignment="Left" VerticalAlignment="Top"
ItemsSource="{StaticResource CombinationOptions}"
SelectedItem="{Binding Potassium}"/>
</DockPanel>
<Button x:Name="SaveIt" Content="Save" Grid.Row="3" Grid.Column="1"/>
</Grid>
</Grid>
And here is the Code Behind for the page:
Class FunWithFocus
Private Sub FertilizerCombinationContainer_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles FertilizerCombinationContainer.Loaded
'FertilizerCombinationContainer.BindingGroup.CancelEdit()'
'FertilizerCombinationContainer.BindingGroup.BeginEdit()'
End Sub
Private Sub FertilizerCombinationContainer_LostFocus(sender As Object, e As System.Windows.RoutedEventArgs) Handles FertilizerCombinationContainer.LostFocus
'This will get fired if the user drops down one of the comboboxes'
End Sub
'This is how I am currently handling the lost focus...but it doesn't fire if the user clicks somewhere that doesn't take keyboard focus'
'Private Sub FertilizerCombinationContainer_IsKeyboardFocusWithinChanged(sender As Object, e As System.Windows.DependencyPropertyChangedEventArgs) Handles FertilizerCombinationContainer.IsKeyboardFocusWithinChanged'
' If FertilizerCombinationContainer.IsKeyboardFocusWithin = False Then'
' FertilizerCombinationContainer.BindingGroup.ValidateWithoutUpdate()'
' If Validation.GetErrors(FertilizerCombinationContainer).Count = 0 Then'
' FertilizerCombinationContainer.BindingGroup.CommitEdit()'
' Dim bg As BindingGroup = FertilizerCombinationContainer.BindingGroup'
' Dim fertilizerCombo As FertilizerCombination = bg.Items(0)'
' Dim proposedNitrogen As Integer'
' Dim proposedPhosphorous As Integer'
' Dim proposedPotassium As Integer'
' Try'
' proposedNitrogen = bg.GetValue(fertilizerCombo, "Nitrogen")'
' proposedPhosphorous = bg.GetValue(fertilizerCombo, "Phosphorous")'
' proposedPotassium = bg.GetValue(fertilizerCombo, "Potassium")'
' ''there was a change: set it'
' fertilizerCombo.SetFertilizerCombination(proposedNitrogen, proposedPhosphorous, proposedPotassium)'
' Catch noValue As System.Windows.Data.ValueUnavailableException'
' ''a binding was not properly bound yet'
' End Try'
' End If'
' End If'
'End Sub'
End Class
If you put a break point on the method that handles FertilizerCombinationContainer's LostFocus event, you will notice that it is fired when you select one of the ComboBoxes even though it is a child of the FertilizerContainer element.
Thank you,
-Frinny

What is wrong with my listbox databinding?

I mostly do databinding on ComboBoxes and DataGrids, and I assumed a ListBox would work the same, but it appears I'm missing something since my ListBox remains blank as I add Scan objects to my observable collection. Any idea what I'm missing here?
<ListBox Height="480" HorizontalAlignment="Left" Margin="551,77,0,0" Name="ListBox_scans" VerticalAlignment="Top" Width="415" ItemsSource="{Binding}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=time}" />
<TextBlock Text="{Binding Path=station_name}"/>
<TextBlock Text="{Binding Path=Barcode}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Scan Class:
Public Class Scan
Public Property Barcode As String
Public FromStation As Station
Public DateTimeUTC As DateTime
Public ScanType As String 'LotID, Employee Badge, Break, Complete, Duplicate
Public Duplicate As Boolean = False
Public IsWIPCleanUp As Boolean = False
Public IsComplete As Boolean = False
Public Property station_name As String
Get
If (Not FromStation Is Nothing) Then
Return FromStation.Name
Else
Return "Station: No Station"
End If
End Get
Set(value As String)
End Set
End Property
Public Property time As String
Get
Return DateTimeUTC.ToLocalTime.ToShortTimeString()
End Get
Set(value As String)
End Set
End Property
End Class
Then I just bind in some main code with:
Private scan_collection As New ObservableCollection(Of Scan)
ListBox_scans.ItemsSource = scan_collection

Binding ListView Throws Window must be the root of the tree. Cannot add Window as a child of Visual

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.
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.
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

Resources