MVVM Binding a combobox - silverlight

I have a very ordinary ViewModel and I am tring to bind a collection of values to a combobox. The problem is nothing is binding. I have checked the ViewModel constructor and the data is being loaded so I suspect its in my XAML but I just cant find out where.
public class OwnerOccupierAccountViewModel : ViewModelBase
{
readonly UserAccountContext _userAccountContext;
readonly LoadOperation<Structure> _loadStructures;
#region Properties
private ObservableCollection<Structure> _structures;
public ObservableCollection<Structure> Structures
{
get { return _structures; }
set
{
_structures = value;
RaisePropertyChanged("Structures");
}
}
private Structure _selectedStructure;
public Structure SelectedStructure
{
get { return _selectedStructure; }
set
{
_selectedStructure = value;
RaisePropertyChanged("SelectedStructure");
}
}
#endregion
public OwnerOccupierAccountViewModel()
{
_userAccountContext = new UserAccountContext();
if (!DesignerProperties.IsInDesignTool)
{
_loadStructures = _userAccountContext.Load(_userAccountContext.GetStructuresQuery());
_loadStructures.Completed += new EventHandler(_loadStructures_Completed);
}
}
void _loadStructures_Completed(object sender, EventArgs e)
{
_structures = new ObservableCollection<Structure>();
foreach (var structure in _loadStructures.Entities)
{
Structures.Add(structure);
}
}
}
<UserControl.Resources>
<viewmodel:OwnerOccupierAccountViewModel x:Key='ViewModel'></viewmodel:OwnerOccupierAccountViewModel>
</UserControl.Resources>
<ComboBox x:Name='cboApartments'
ItemsSource='{Binding Structures,Source={StaticResource ViewModel},Mode=TwoWay}'
Width='200' />

Try intializing your ObservableCollection of Structures like that:
void _loadStructures_Completed(object sender, EventArgs e)
{
Structures = new ObservableCollection<Structure>(_loadStructures.Entities);
}
and as it was mentioned earlier i think you should change order here:
if (!DesignerProperties.IsInDesignTool)
{
//other code before
//_loadStructures = ...
_loadStructures.Completed += new EventHandler(_loadStructures_Completed);
//and now start loading
}
I did similar, very simple app to check what could gone wrong, but everything works well. I will show you my code, so you can compare and maybe you will find some bugs in your solution.
Structure.cs
public class Structure
{
public Structure(string name)
{
Name = name;
}
public string Name { get; set; }
}
StructureService.cs
public class StructureService
{
public void GetAllStructures(Action<IList<Structure>> CompleteCallback)
{
var temp = new List<Structure>()
{
new Structure("Str1"),
new Structure("Str2"),
new Structure("Str3"),
new Structure("Str4"),
new Structure("Str5"),
new Structure("Str6"),
new Structure("Str7")
};
CompleteCallback(temp);
}
}
ViewModelBase.cs
public class ViewModelBase : INotifyPropertyChanged
{
protected void RaisePropertyChanged(string prop)
{
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs(prop));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
OwnerOccupierAccountViewModel:
public class OwnerOccupierAccountViewModel : ViewModelBase
{
StructureService service;
public OwnerOccupierAccountViewModel()
{
if (!DesignerProperties.IsInDesignTool)
{
service = new StructureService();
service.GetAllStructures((result) =>
{
Structures = new ObservableCollection<Structure>(result);
});
}
}
private ObservableCollection<Structure> _structures;
public ObservableCollection<Structure> Structures
{
get { return _structures; }
set
{
_structures = value;
RaisePropertyChanged("Stuctures");
}
}
private Structure _selectedStructure;
public Structure SelectedStructure
{
get { return _selectedStructure; }
set
{
_selectedStructure = value;
RaisePropertyChanged("SelectedStructure");
}
}
}
MainPage.xaml:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<vm:OwnerOccupierAccountViewModel x:Key="ViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<ComboBox x:Name="cboApartments"
ItemsSource='{Binding Structures,Source={StaticResource ViewModel},Mode=TwoWay}'
SelectedItem="{Binding SelectedStructure, Source={StaticResource ViewModel},Mode=TwoWay}"
Width="100" Height="30">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</UserControl>
If i were in your shoes i wll change xaml to such view:
SuggestedView:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.DataContext>
<vm:OwnerOccupierAccountViewModel/>
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="White">
<ComboBox x:Name="cboApartments"
ItemsSource='{Binding Structures, Mode=TwoWay}'
SelectedItem="{Binding SelectedStructure, Mode=TwoWay}"
Width="100" Height="30">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</UserControl>
but i understand that it is somehow impossible in your scenario?

Try replacing this line:
_structures = new ObservableCollection<Structure>();
with this:
Structures = new ObservableCollection<Structure>();
And set the binding of ComboBox to OneWay.
Edited to update solution:
Set DisplayMemberPath property of ComboBox as well:
DisplayMemberPath="StructureName"

The binding will only fire when the property is changed. The line setting the backing variable won't call the RaisePropertyChanged event. Even if it did it would be empty at this point anyway and you'd end up with an empty list.
_structures = new ObservableCollection<Structure>();
When you then add to the collection you aren't changing the property value, you're calling the getter so again the RaisePropertyChanged won't fire.
Structures.Add(structure);
You need to build a local collection then use that as the value for the Structures property. This should cause the binding to be triggered.
var structures = new ObservableCollection<Structure>();
foreach ...
Structures = structures;

You are binding directly to the ViewModel key as a source, but is it set as a DataContext anywhere?

Related

How to bind textbox value to view-model and update it via button command? [duplicate]

This question already has answers here:
Issue with DependencyProperty binding
(3 answers)
How to pass data from MainWindow to a User Control that's inside the MainWindow?
(1 answer)
Closed 1 year ago.
Alright, so I'm new to MVVM and trying to do some data-binding and can't get it working.
I built a WPF application with two user-controls UC1 and UC2 and a View-Model Class VM1.
UC1 consists of a button whose command is specified in VM1 and UC2 consists of three text boxes whose texts are bound to properties in VM1. So what I want is, when I click on the button the text of each textbox must change. But when I click the button nothing happens. See below for the code.
ViewModel Class - VM1:
namespace TestApp.ViewModels
{
public class VM1 : INotifyPropertyChanged
{
#region Definations
private double heading;
private double attitude;
private double bank;
public double Heading
{
get { return heading; }
set
{
heading = value;
RaisePropertyChanged("Heading");
}
}
public double Attitude
{
get { return attitude; }
set
{
attitude = value;
RaisePropertyChanged("Attitude");
}
}
public double Bank
{
get { return bank; }
set
{
bank = value;
RaisePropertyChanged("Bank");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
#endregion
//public TrayModel TrayModel { get; set; }
public ICommand UpdateViewAxesToFrontCommand { get; set; }
public VM1()
{
UpdateViewAxesToFrontCommand = new RelayCommand(UpdateViewAxesToFront, canExecuteMethod);
}
public bool canExecuteMethod(object parameter)
{
return true;
}
public void UpdateViewAxesToFront(object param)
{
Attitude = 10;
Heading = 0;
Bank = 0;
}
}
}
UC1:
<UserControl x:Class="TestApp.UserControls.UC1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:VM="clr-namespace:TestApp.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestApp.UserControls"
mc:Ignorable="d">
<UserControl.DataContext>
<VM: VM1/>
</UserControl.DataContext>
<hc:ButtonGroup>
<Button Style="{StaticResource ButtonIcon}" Command="{Binding Path=UpdateViewAxesToFrontCommand, UpdateSourceTrigger=PropertyChanged}" hc:IconElement.Geometry="{StaticResource CubeFontFaceGeometry}"/>
</hc:ButtonGroup>
</UserControl>
UC2:
<UserControl x:Class="TestApp.UserControls.UC2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:VM="clr-namespace:TestApp.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestApp.UserControls"
mc:Ignorable="d">
<UserControl.DataContext>
<VM: VM1/>
</UserControl.DataContext>
<StackPanel>
<TextBox Text="{Binding Attitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Bank, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Heading, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</UserControl>
I've also set DataContext in code-behind of each user-control as follows.
InitilizeComponent();
DataContext = new ViewModels.VM1();
Upon loading, the values in each text boxes are set to 0, and once I click the button the values remain 0 and don't change to 10, 0, 0 as expected.

WPF treeview with HierarchicalDataTemplate shows only 1 item

I am trying to bind to a WPF treeview but I am getting unexpected results. I bind to my viewmodel which appears to work as I get a single item but it does not allow me to expand to child items. I cant see what I'm doing wrong. Does anyone have any ideas?
I have the following model
public class Folder
{
public string Name { get; set; }
public IEnumerable<Folder> Subfolders { get; set; }
}
I have the following view model
public class Vm : INotifyPropertyChanged
{
private IEnumerable<Folder> _items;
public Vm()
{
var x = new List<Folder>();
x.Add(new Folder()
{
Name = "Item1",
Subfolders = new List<Folder>()
{
new Folder()
{
Name = "SubItem1", Subfolders = new List<Folder>()
{
new Folder() { Name = "SubItem2", Subfolders = new List<Folder>()}
}
}
}
});
Items = x;
}
public IEnumerable<Folder> Items
{
get => _items;
set
{
_items = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
My Xaml looks like
<Window x:Class="WpfApp5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp5"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TreeView Height="450" Width="800" ItemsSource="{Binding Path=Items}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Folder}" >
<TextBlock Margin="5,0,0,0" FontWeight="Bold" Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
Its ok I found it. I needed to add a Items source value to the HierarchicalDataTemplate of Subitems

Silverlight 5 Binding - Why isn't this working?

I can bind a combobox in the codebehind like this:
private void comboBox1_Loaded(object sender, RoutedEventArgs e)
{
var combo = sender as ComboBox;
App.SchedulerVM = new ScheduleViewModel();
combo.DataContext = App.SchedulerVM;
combo.ItemsSource = App.SchedulerVM.Frequency;
}
This works - my combobox has the items from the Frequency List in the SchedulerVM object.
However, I don't want to do any of this in the codebehind. But the ways I've done this in WP7 before aren't working here. If I comment out the last line in the Loaded method above and try to set the ItemsSource in XAML, it doesn't work - nothing shows up:
<ComboBox Name="comboBox1" Loaded ="comboBox1_Loaded" ItemsSource="{Binding
Frequency}" />
This doesn't work either:
<ComboBox Name="comboBox1" Loaded ="comboBox1_Loaded" ItemsSource="{Binding
App.SchedulerVM.Frequency}" />
Nor this:
<ComboBox Name="comboBox1" Loaded ="comboBox1_Loaded" ItemsSource="{Binding
SchedulerVM.Frequency}" />
Ideally, the DataContext wouldn't have to be explicitly set in the codebehind for this control either, it would be inherited from the LayoutRoot, where I've set it in the codebehind. But that's step 2 of my troubleshooting here.
What am I doing wrong? '
Thanks!
Edit
The ScheduleViewModel looks like this:
namespace SchedulerUI.ViewModels
{
public class ScheduleViewModel : INotifyPropertyChanged
{
//private properties
private Schedule _thisSchedule;
//public properties
public Schedule ThisSchedule
{
get { return _thisSchedule; }
set
{
if (value != _thisSchedule)
{
NotifyPropertyChanged("ThisSchedule");
}
_thisSchedule = value;
}
}
public List<string> Frequency = new List<string>();
public string Test;
//constructors
public ScheduleViewModel()
{
Frequency.AddRange(new string[] { "Daily", "Weekly", "Monthly" });
Test = "This is only a test.";
}
//INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Here's the entire XAML:
<UserControl x:Class="SchedulerUI.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
<ComboBox Height="23" HorizontalAlignment="Left" Margin="34,41,0,0" Name="comboBox1" Loaded ="comboBox1_Loaded" VerticalAlignment="Top" Width="120" ItemsSource="{Binding Frequency}" />
<TextBox BorderBrush="Black" HorizontalAlignment="Left" Margin="34,41,0,0" Width="100" Height="100" DataContext="LayoutRoot.DataContext" Text="{Binding Test}" />
</Grid>
</UserControl>
Here's the entire codebehind:
namespace SchedulerUI
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
App.SchedulerVM = new ScheduleViewModel();
comboBox1.DataContext = App.SchedulerVM;
List<string> testlist = App.SchedulerVM.Frequency;
string teststring = App.SchedulerVM.Test;
}
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
//App.SchedulerVM = new ScheduleViewModel();
//var root = sender as Grid;
//if (root != null)
//{
// root.DataContext = App.SchedulerVM;
//}
}
private void comboBox1_Loaded(object sender, RoutedEventArgs e)
{
//var combo = sender as ComboBox;
//App.SchedulerVM = new ScheduleViewModel();
//combo.DataContext = App.SchedulerVM;
//combo.ItemsSource = App.SchedulerVM.Frequency;
}
}
}
You binding is not working, because:
when you set ItemsSource in XAML its get executed first and it tries to bind the wrong/empty DataContext
then the Loaded event is raised which will set the correct DataContext but your already existing binding won't be refreshed automatically.
If you have to set the DataContext in the codebehind do it in your views constructor:
public YourView()
{
InitializeComponent();
combo.DataContext = App.SchedulerVM;
}
Then the following binding should work:
<ComboBox Name="comboBox1" ItemsSource="{Binding Frequency}" />
The databinding in WPF/Silverlight needs public properties. Currently Frequency is a public field on your viewmodel change it to a property and everthing should work:
private List<string> frequency = new List<string>();
public List<string> Frequency { get { return frequency; } set { frequency = value; }
And that is why it worked your initial loaded event because you didn't used databind there but you just set the combo.ItemsSource.

Binding a ComboBox entirely in XAML

I have a ComboBox on a silverlight control, that I want to bind. Sounds simple, except what I'm finding is that because the data for the ItemsSource comes from a web service asynchronously, I need to use the code behind to bind the SelectedValue only after the data has come back.
The collection that the data goes in implements INotifyCollectionChanged and INotifyPropertyChanged, so it should all be working, and indeed the combo box loads properly, but there is no value pre-selected.
What I think is happening is that the SelectedValue is getting bound before the collection has loaded - when the combobox is empty - so nothing is selected, and then later when the data comes in, the combobox is populated, but it is not checking the selected value again.
So whilst I have this working if I use code behind to hook up events and creating bindings in code, I'd like to move this all to XAML with something like:
<ComboBox HorizontalAlignment="Stretch" Margin="5,3,9,127" Name="cboCategoryID" Grid.Row="4" Grid.Column="1"
ItemsSource="{StaticResource Categories}"
SelectedValue="{Binding CategoryID, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}"
SelectedValuePath="CategoryID"
DisplayMemberPath="Caption"
VerticalAlignment="Center">
</ComboBox>
This correctly loads items, but doesn't bind the selected value. If I put the following code in the code-behind, it all works:
public MainControl()
{
InitializeComponent();
CategoryCollection cats = new CategoryCollection();
cats.Dispatcher = this.Dispatcher;
cats.LoadComplete += new EventHandler(cats_LoadComplete);
cboCategoryID.ItemsSource = cats;
cats.LoadAll();
}
private void cats_LoadComplete(object sender, EventArgs e)
{
cboCategoryID.SetBinding(ComboBox.SelectedValueProperty, new System.Windows.Data.Binding("CategoryID"));
}
Is there a way to do this without resorting to code behind?
Are you using mvvm? If so, you can try to set the ItemsSource and SelectedItem in the callback of the web service, or take a look at this post from Kyle.
http://blogs.msdn.com/b/kylemc/archive/2010/06/18/combobox-sample-for-ria-services.aspx
you are already using a collection that notifies of changes, so if the value that you are binding the SelectedValue to is notifying of changes, then all you have to do is set that property after the values are loaded from the webservice. it SHOULD update the combobox automatically, allowing you to do your binding purely in xaml.
public myObject CategoryID { get {....}
set {
this.categoryID = value;
RaisePropertyChanged("CategoryID");}
public void DataLoadedHandler()
{
CategoryID = 34; // this will cause the binding to update
}
take a look at this simple sample:
XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" xmlns:local="clr-namespace:StackoverflowQuestions.Silverlight" xmlns:sdk1="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="StackoverflowQuestions.Silverlight.MainPage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<DataTemplate x:Key="Item">
<TextBlock Text="{Binding PropertyToBeWatched}" />
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<!--<sdk:DataGrid ItemsSource="{Binding MyList}" RowStyle="{StaticResource Style1}">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding PropertyToBeWatched}" Header="Property1"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>-->
<ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" Height="50" VerticalAlignment="Top" ItemTemplate="{StaticResource Item}" />
</Grid>
</UserControl>
Codebehind:
public partial class MainPage : UserControl, INotifyPropertyChanged
{
private ObservableCollection _myList;
private CustomClass _selectedItem;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<CustomClass> MyList
{
get { return _myList ?? (_myList = new ObservableCollection<CustomClass>()); }
set
{
_myList = value;
RaisePropertyChanged("MyList");
}
}
public CustomClass SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
protected void RaisePropertyChanged(string propertyname)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyname));
}
public MainPage()
{
InitializeComponent();
this.DataContext = this;
MyList.Add(new CustomClass() { PropertyToBeWatched = "1"});
MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
SelectedItem = MyList[1]; //Here is where it happens
}
}
By binding the SelectedItem of the ComboBox to an entity, we can achieve what you want. This works TwoWay ofcourse.
Hope this helps. :D

Binding recursively in a WPF TreeView

I am trying to bind recursively to the children of an item in a TreeView. From what I can see on MSDN HierarchicalDataTemplate is the way to go, but thus far I've only been partially successful.
My class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DocumentText test = new DocumentText();
this.DataContext = test;
for (int i = 1; i < 5; i++)
{
test.AddChild();
}
foreach (DocumentText t in test.Children)
{
t.AddChild();
t.AddChild();
}
}
}
partial class DocumentText
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public override string ToString()
{
return Name;
}
public List<DocumentText> _children;
public List<DocumentText> Children
{
get { return this._children; }
}
public DocumentText()
{
_name = "Test";
_children = new List<DocumentText>();
}
public void AddChild()
{
_children.Add(new DocumentText());
}
}
My XAML:
In mainview.xaml:
<Window x:Class="treetest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TreeView Name="binderPanel" DockPanel.Dock="Left"
MinWidth="150" MaxWidth="250" Background="LightGray"
ItemsSource="{Binding Children}">
</TreeView>
</Grid>
</Window>
In app.xaml:
<HierarchicalDataTemplate x:Key="BinderTemplate"
DataType="{x:Type src:DocumentText}" ItemsSource="{Binding Path=/Children}">
<TreeViewItem Header="{Binding}"/>
</HierarchicalDataTemplate>
This code produces a list of the first children, but the nested children are not displayed.
The primary problem in what you posted is that you haven't connected the HierarchicalDataTemplate as the TreeView's ItemTemplate. You need to either set ItemTemplate="{StaticResource BinderTemplate}" or remove the x:Key to apply the template to all DocumentText instances. You should also change the TreeViewItem in the template to a TextBlock - the TreeViewItem is generated for you and what you put in that template is applied to it as a HeaderTemplate.

Resources