I am having some serious trouble creating a WPF TreeView with an Object databinding.
The application is config file editor. I have defined an Object structure which can be serialized to the correct XML format.
The problem I am having is formatting the object instance in the TreeView showing the correct hierarchy. The TreeView will only render the Channel node, and nothing else.
public class Objects
{
public List<Channel> Channels { get; set; }
}
public class Channel
{
public string Id { get; set; }
public string Name { get; set; }
public Reader Reader { get; set; }
public Filters Filters { get; set; }
public Router Router { get; set; }
public Persister Persister { get; set; }
}
public class Filters : ArrayList
{
public string StopOnFailure { get; set; }
}
public class Reader
{
public string Id { get; set; }
public string Name { get; set; }
}
All the child classes of Channel
contain properties Id
and Name
. The Filters class is a collection of other types with the same property definition.
Here is the XAML
<Window.Resources>
<ObjectDataProvider x:Key="data"/>
<DataTemplate DataType="{x:Type ConfigurationEditor:Channel}">
<WrapPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
<TextBlock Text=" [" />
<TextBlock Text="{Binding Path=Id}" />
<TextBlock Text="]" />
</WrapPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<TreeView Margin="12,12,12,96" Name="treeView1" ItemsSource="{Binding Source={StaticResource data}, Path=Channels}">
</TreeView>
</Grid>
The code behind to create the data instance
Objects config;
var serializer = new XmlSerializer(typeof(Objects));
using (var stream = new FileStream(@"C:\test.xml", FileMode.Open))
{
config = (Objects)serializer.Deserialize(stream);
}
var dp = (ObjectDataProvider)FindResource("data");
dp.ObjectInstance = config;
I've looked at countless examples but I still can figure out what I am doing wrong. Thanks for the help.
Update:
<HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Objects}" ItemsSource="{Binding Path=Channels}"/>
<HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Channel}" ItemsSource="Binding Path=Reader}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
No change to the TreeView
. With this change I still have only the Channel
listed, and nothing else.
Expanding on @Gimalay's answer, the problem is that the TreeView
doesn't know where to get the data for any child nodes. You inform the TreeView
by using a HierarchialDataTemplate
, rather than a DataTemplate
:
<HierarchialDataTemplate DataType="{x:Type ConfigurationEditor:Channel}"
ItemsSource="...">
<WrapPanel>
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
<TextBlock Text=" [" />
<TextBlock Text="{Binding Path=Id}" />
<TextBlock Text="]" />
</WrapPanel>
</HierarchialDataTemplate>
The main difference between the two is the ItemsSource
attribute. This is a binding expression that returns a collection of objects to use as child nodes.
The problem is that you have a few properties to get children from, not just one. You either need to combine them all into one property, or add another property that returns all of the child nodes.
Finally, you'll need to define a DataTemplate
for each child item type, so that the TreeView
knows how to display them (you can use a HierarchialDataTemplate
for the children as well, if they in turn have child nodes).