WPF Treeview and ListBox synchronization - wpf

I have a treeview which shows a hierarchy of items where each item has a checkbox. I would like to show below the treeview a listbox with all the checked items. How to achieve such functionality using MVVM pattern?
Thanks in advance
Lukasz Glaz

Here's an example:
ViewModel
public class TreeNodeViewModel : ViewModelBase
{
#region Constructors
public TreeNodeViewModel(string text, params TreeNodeViewModel[] nodes)
: this(text, new ObservableCollection<TreeNodeViewModel>(nodes))
{
}
public TreeNodeViewModel(string text, ObservableCollection<TreeNodeViewModel> nodes)
{
Text = text;
Nodes = nodes;
foreach (var node in Nodes)
{
node.Parent = this;
}
Nodes.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Nodes_CollectionChanged);
}
#endregion
#region Private methods
private void Nodes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (var node in e.OldItems.Cast<TreeNodeViewModel>())
{
node.Parent = null;
}
foreach (var node in e.NewItems.Cast<TreeNodeViewModel>())
{
node.Parent = this;
}
OnPropertyChanged("CheckedNodes");
}
private void NotifyParent()
{
if (Parent != null)
{
Parent.OnPropertyChanged("CheckedNodes");
Parent.NotifyParent();
}
}
#endregion
#region Private data
private string _text;
private bool _isChecked;
private TreeNodeViewModel _parent;
#endregion
#region Public properties
public string Text
{
get { return _text; }
set
{
if (value != _text)
{
_text = value;
OnPropertyChanged("Text");
}
}
}
public bool IsChecked
{
get { return _isChecked; }
set
{
if (value != _isChecked)
{
_isChecked = value;
NotifyParent();
OnPropertyChanged("IsChecked");
}
}
}
public ObservableCollection<TreeNodeViewModel> Nodes { get; private set; }
public IEnumerable<TreeNodeViewModel> CheckedNodes
{
get
{
foreach (var node in Nodes)
{
if (node.IsChecked)
yield return node;
foreach (var child in node.CheckedNodes)
{
yield return child;
}
}
}
}
public TreeNodeViewModel Parent
{
get { return _parent; }
private set
{
if (value != _parent)
{
_parent = value;
OnPropertyChanged("Parent");
}
}
}
#endregion
}
XAML
<TreeView Grid.Row="0" ItemsSource="{Binding Nodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}" />
<TextBlock Text="{Binding Text}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListBox Grid.Row="1" ItemsSource="{Binding CheckedNodes}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code-behind
this.DataContext = new TreeNodeViewModel(
null,
new TreeNodeViewModel(
"1",
new TreeNodeViewModel(
"1.1",
new TreeNodeViewModel("1.1.1"),
new TreeNodeViewModel("1.1.2")),
new TreeNodeViewModel("1.2")),
new TreeNodeViewModel(
"2",
new TreeNodeViewModel("2.1"),
new TreeNodeViewModel(
"2.2",
new TreeNodeViewModel("2.2.1"))));
Note that it is a rather naive implementation, it could easily be improved... For instance, the whole list of checked nodes is reevaluated every time a node is checked/unchecked, which could lead to bad performance for a big TreeView

Related

wpf ListItem SelectedValue Object is always null

I have a simple ListBox and a TextBox as under.I want to display the selectedvalue property of Listbox in the textbox,but my ViewModel's selected object is always null.
What am i missing here?
My XAML
<StackPanel>
<Canvas>
<TextBox x:Name="TxtMail" Width="244" FontSize="14" Canvas.Left="36" Canvas.Top="34" Height="20" Text="{Binding CurrentRec.Name,Mode=OneWay}" />
<ListBox x:Name="AllMatching" Width="{Binding ElementName=TxtMail,Path=Width}" Height="100" Canvas.Top="54" Canvas.Left="36" DisplayMemberPath="Name" SelectedItem="{Binding CurrentRec,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedValue="Name" SelectedValuePath="Name" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" />
<Button Content="Test" x:Name="cmdtest" Click="cmdtest_Click"/>
</Canvas>
My ViewModel:
public class VM_Data : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int p_ID;
public double p_SP, p_CP;
public string p_Name;
public List<DM_Data> AllData;
public DM_Data CurrentRec;
public VM_Data()
{
LoadData();
}
public int ID
{
get { return p_ID; }
set
{
if (p_ID != value)
{
RaisePropertyChangedEvent("ID");
p_ID = value;
}
}
}
public double SP
{
get { return p_SP; }
set
{
if (p_SP != value)
{
RaisePropertyChangedEvent("SP");
p_SP = value;
}
}
}
public double CP
{
get { return p_CP; }
set
{
if (p_CP != value)
{
RaisePropertyChangedEvent("CP");
p_CP = value;
}
}
}
public string Name
{
get { return p_Name; }
set
{
if (p_Name != value)
{
RaisePropertyChangedEvent("Name");
p_Name = value;
}
}
}
private void LoadData()
{
AllData = new List<DM_Data>();
string[] strNames = "Jatinder;Shashvat;shashikala;shamsher;shahid;justin;jatin;jolly;ajay;ahan;vijay;suresh;namita;nisha;negar;zenith;zan;zen;zutshi;harish;hercules;harman;ramesh;shashank;mandeep;aman;amandeep;amarjit;asim;akshay;amol;ritesh;ritivik;riz;samana;samaira;bhagwandass;bhagwan;bhawna;bhavna".Split(';');
for(int i=0;i<=strNames.GetUpperBound(0);i++)
{
DM_Data NewRec = new DM_Data();
NewRec.CP = new Random().Next(200, 400);
NewRec.SP = new Random().Next(1, 10);
NewRec.ID = i + 1;
NewRec.Name = strNames[i];
AllData.Add(NewRec);
}
AllData = AllData.OrderBy(item => item.Name).ToList();
}
private void RaisePropertyChangedEvent(string Property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(Property));
}
}
}
My DataModel
public class DM_Data
{
public int p_ID;
public double p_SP, p_CP;
public string p_Name;
public int ID
{
get { return p_ID; }
set { p_ID = value; }
}
public double SP
{
get { return p_SP; }
set { p_SP = value; }
}
public double CP
{
get { return p_CP; }
set { p_CP = value; }
}
public string Name
{
get { return p_Name; }
set { p_Name = value; }
}
MainWindow.Xaml.cs
public partial class MainWindow : Window
{
VM_Data ViewModel;
public MainWindow()
{
InitializeComponent();
ViewModel = new VM_Data();
this.DataContext = ViewModel;
AllMatching.ItemsSource = ViewModel.AllData;
}
private void cmdtest_Click(object sender, RoutedEventArgs e)
{
DM_Data crec = ViewModel.CurrentRec;
}
}
CurrentRec must be a property that raises the PropertyChanged event:
private DM_Data _currentRec;
public DM_Data CurrentRec
{
get { return _currentRec; }
set { _currentRec = value; RaisePropertyChangedEvent("CurrentRec"); }
}
In the code you have posted, it is a field and you cannot bind to fields:
public DM_Data CurrentRec;
You can't bind to fields! CurrentRec must be a property. At now it is a field.
Why do you set ItemsSource in code-behind? Set it in XAML.
You should call RaisePropertyChangedEvent after you've changed backing field, not before.
It is not right pattern for events raising: if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(Property)); } You need to save event delegate to variable first or use ?.Invoke.
Don't create new instances of Random on every iteration of loop because you will get equal values. Create the only one outside of the loop and use it.
What you are doing is kind of MVVM, but not really.
Here is a quick fix anyway:
Please take a look at the Bindings.
<StackPanel>
<Canvas>
<TextBox x:Name="TxtMail" Width="244" FontSize="14" Canvas.Left="36" Canvas.Top="34" Height="20" Text="{Binding ElementName=AllMatching, Path=SelectedItem.Name}" />
<ListBox x:Name="AllMatching"
Width="{Binding ElementName=TxtMail,Path=Width}"
Height="100"
Canvas.Top="54"
Canvas.Left="36"
DisplayMemberPath="Name"
SelectedItem="{Binding CurrentRec,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto" />
<Button Content="Test" x:Name="cmdtest" Click="cmdtest_Click"/>
</Canvas>
</StackPanel>
I think you get the idea at: Text="{Binding ElementName=AllMatching, Path=SelectedItem.Name}".
Aditional Information
First:
You fire to early dude. Please first assign the value and then say its changed.
if (p_Name != value)
{
RaisePropertyChangedEvent("Name");
p_Name = value;
}
Second:
Use a ObservableCollection<DM_Data> to let your ListBox know about changes.
Third:
Use the posibility of Binding
Remove AllMatching.ItemsSource = ViewModel.AllData; and go like
<ListBox x:Name="AllMatching"
ItemsSource="{Binding Path=AllData}"
...
/>
And after all of this - please man check out some tutorials. And also refactor your code from VM_Data to DataViewModel thank you sir.

How remove list to listbox with Button using MVVM silverlight

My Problem, I can't remove list in my listbox from browser, but when i debug in my code data list has removed.
View Model
private List<Customer> _listCustomer = new List<Customer>();
public List<Customers> ListCustomers
{
get { return _listCustomers; }
set { _listCustomers = value; OnPropertyChanged("ListCustomers"); }
}
private ICommand _removeCommand;
public ICommand RemoveCommand
{
get { return _removeCommand ?? (_removeCommand = new RelayCommand(param => ButtonRemoveCustomer(), null)); }
set { OnPropertyChanged("ListCustomers"); }
}
private void ButtonRemoveCustomer()
{
ListCustomers.Remove(this.SelectCustomer);
this.SelectCustomer = null;
}
My View
<Intersoft:UXListBox x:Name="CustData" Width="200" MaxHeight="500" SelectedItem="{Binding SelectCustomer, Mode=TwoWay}"
ItemsSource="{Binding ListCustomers, Mode=TwoWay}" ItemTemplate="{StaticResource DataListTemplate}"
VerticalScrollBarVisibility ="Visible" HorizontalScrollBarVisibility="Visible"/>
<Intersoft:UXButton Content="Remove List" Command="{Binding RemoveCommand, Mode=TwoWay}" Width="100"/>
How to fix my code ??
private void ButtonRemoveCustomer()
{
ListCustomers.Remove(this.SelectCustomer);
OnPropertyChanged("ListCustomers");
this.SelectCustomer=null;
}

WPF DataGrid with DataGrid in RowDetailsTemplate

My previous post about detecting property changes in the VM wasn't in depth enough, so I'm posting this
I have a grid of Jobs. Each job can have one or more employees.
The DataGrid's RowDetailsTemplate contains another grid to show the employees. So to parent grid is bound to a list of Jobs. The inner grid is bound to a list of Employees that is on the Job model.
The Job Model:
public class Job : _Base
{
private string _JobName = string.Empty;
public string JobName
{
get { return _JobName; }
set
{
if (_JobName != value)
{
_JobName = value;
RaisePropertyChanged("JobName");
}
}
}
private string _JobNumber = string.Empty;
public string JobNumber
{
get { return _JobNumber; }
set
{
if (_JobNumber != value)
{
_JobNumber = value;
RaisePropertyChanged("JobNumber");
}
}
}
private ObservableCollection<Employee> _Employees;
public ObservableCollection<Employee> Employees
{
get { return _Employees; }
set
{
if (_Employees != value)
{
if (_Employees != value)
{
_Employees = value;
RaisePropertyChanged("Employees");
}
}
}
}
private Employee _SelectedEmployee;
public Employee SelectedEmployee
{
get { return _SelectedEmployee; }
set
{
if (_SelectedEmployee != value)
{
if (_SelectedEmployee != value)
{
_SelectedEmployee = value;
RaisePropertyChanged("SelectedEmployee");
}
}
}
}
public Job()
{
Employees = new ObservableCollection<Employee>();
}
}
The Employee model
public class Employee : _Base
{
private string _EmployeeName = string.Empty;
public string EmployeeName
{
get { return _EmployeeName; }
set
{
if (_EmployeeName != value)
{
_EmployeeName = value;
RaisePropertyChanged("EmployeeName");
}
}
}
private bool _IsChecked = false;
public bool IsChecked
{
get { return _IsChecked; }
set
{
if (_IsChecked != value)
{
_IsChecked = value;
RaisePropertyChanged("IsChecked");
}
}
}
}
The XAML
<DataGrid ItemsSource="{Binding Jobs}"
SelectedItem="{Binding SelectedJob}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Job Name" Binding="{Binding JobName}" />
<DataGridTextColumn Header="Job Number" Binding="{Binding JobNumber}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<DataGrid ItemsSource="{Binding Employees}"
SelectedItem="{Binding SelectedEmployee}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridCheckBoxColumn Binding="{Binding IsChecked}"/>
<DataGridTextColumn Binding="{Binding EmployeeName}"/>
</DataGrid.Columns>
</DataGrid>
<Button Margin="5"
Height="23"
Width="75"
HorizontalAlignment="Left"
Content="Remove"/>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
The MainWindowViewModel
public class MainWindowViewModel : _Base
{
private ObservableCollection<Job> _Jobs;
public ObservableCollection<Job> Jobs
{
get { return _Jobs; }
set
{
if (_Jobs != value)
{
if (_Jobs != value)
{
_Jobs = value;
RaisePropertyChanged("Jobs");
}
}
}
}
private Job _SelectedJob;
public Job SelectedJob
{
get { return _SelectedJob; }
set
{
if (_SelectedJob != value)
{
if (_SelectedJob != value)
{
_SelectedJob = value;
RaisePropertyChanged("SelectedJob");
}
}
}
}
public MainWindowViewModel()
{
this.PropertyChanged += new PropertyChangedEventHandler(MainWindowViewModel_PropertyChanged);
}
void MainWindowViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName.Trim().ToLower() == "ischecked")
{
int x = 1;
}
}
}
I have a couple of questions:
1) The SelectedEmployee property on the Job model does not fire when I click an employee in the inner grid.
2) The MainWindowViewModel_PropertyChanged does not fire when an employee is selected.
3) Notice the button below the inner grid. How do I bind its command to MainWindowVM?
As you have DataGridinside DataGrid's row, so the above DataGrid is somehow eating up the selectionchange for the inner DataGrid. To solve this, you will need to forcefully update the binding source for the child DataGrid. For doing so capture the SelectionChanged event for the inner DataGrid and in the handler do the following.
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid grid = e.OriginalSource as DataGrid;
var expression = grid.GetBindingExpression(DataGrid.SelectedItemProperty);
expression.UpdateSource();
}
MainwindowVM does not have any ischecked property thats why its propertychanged for that property is not firing.
To solve this you need to do couple of things. The problem is DataGrid cell and rows does not inherit the DataContext as they don't come under its visual tree. So to solve this you will have to use the BindingProxy to take the windows DataContext to your button in rowdetails of DataGrid
Define Binding Proxy class as below:
public class MyBindingProxy : Freezable
{
public static readonly DependencyProperty BindingDataProperty =
DependencyProperty.Register("BindingData", typeof(object),
typeof(MyBindingProxy), new UIPropertyMetadata(null));
protected override Freezable CreateInstanceCore()
{
return new MyBindingProxy();
}
public object BindingData
{
get { return (object)GetValue(BindingDataProperty); }
set { SetValue(BindingDataProperty, value); }
}
}
Now in the resources of your window (where DataGrid is) create the instance of proxy and set the BindingData to the DataContext of the Window i.e MainWindowViewModel as:
<Window.Resources>
<local:MyBindingProxy x:Key="myproxy" BindingData="{Binding}" />
</Window.Resources>
Now just set command as below on the button:
<Button Margin="5"
Height="23"
Width="75"
HorizontalAlignment="Left"
Content="Remove"
Command="{Binding BindingData.MyCommand, Source={StaticResource myproxy}}"/>

Selected items of listview checkbox in MVVM WPF

I want to pass selected items of listview checkbox in view model, later I will use further process to store in database.
Code in the FormWeek.xaml as
<Window.DataContext>
<Binding Source="{StaticResource Locator}" Path="TaskExecDefModel"></Binding>
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ItemDataTemplate">
<CheckBox
x:Name="checkbox"
Content="{Binding}" Command="{Binding CheckBoxCommand}" CommandParameter="{Binding ElementName=checkedListView, Path=SelectedItems}"
IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
</DataTemplate>
</ResourceDictionary>
<StackPanel Grid.Column="1" Grid.Row="3" Margin="5">
<CheckBox x:Name="selectAll" Content="Select all" Click="OnSelectAllChanged"/>
<ListView x:Name="checkedListView" SelectionMode="Multiple" ItemsSource="{Binding CollectionOfDays}" DataContext="{Binding}"
ItemTemplate="{StaticResource ItemDataTemplate}" SelectedValue="WorkingDay"
CheckBox.Unchecked="OnUncheckItem" SelectionChanged="SelectDays" SelectedItem="{Binding SelectedItems}">
</ListView>
</StackPanel>
Code in FormWeek.xaml.cs
private void SelectDays(object sender, SelectionChangedEventArgs e)
{
(this.DataContext as TaskExecDefinitionViewModel).OnCheckBoxCommand(checkedListView.SelectedItems,true);
}
My View Model TaskWeek.cs as follows
//Declaration
private RelayCommand<object> _checkBoxCommand;
public ObservableCollection<string> CollectionOfDays { get; set; }
public ObservableCollection<string> SelectedItems { get; set; }
public RelayCommand<object> CheckBoxCommand
{
get
{
if (_checkBoxCommand == null)
{
_checkBoxCommand = new RelayCommand<object>((args) => OnCheckBoxCommand(args,true));
// _checkBoxCommand = new RelayCommand(() => OnCheckBoxCommand(object args));
}
return _checkBoxCommand;
}
}
//Constructor
CollectionOfDays = new ObservableCollection<string>();
//Method
private void GetWeekDays()
{
try
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
CollectionOfDays.Add("Saturday");
CollectionOfDays.Add("Sunday");
CollectionOfDays.Add("Monday");
CollectionOfDays.Add("Tuesday");
CollectionOfDays.Add("Wednesday");
CollectionOfDays.Add("Thursday");
CollectionOfDays.Add("Friday");
}));
}
catch(Exception Ex)
{
MessageBox.Show(Ex.Message, "TaskWeek:GetWeekDays");
}
}
public void OnCheckBoxCommand(object obj, bool _direction)
{
try
{
if (SelectedItems == null)
SelectedItems = new ObservableCollection<string>();
if (obj != null)
{
SelectedItems.Clear();
StringBuilder items = new StringBuilder();
if (_direction)
{
foreach (string item in CollectionOfDays)
{
items.AppendFormat(item + ",");
}
}
MessageBox.Show(items.ToString());
}
else
SelectedItems.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "TaskDefinition:OnCheckBoxCommand");
}
}
And below is button click commond to save the data.
<Button Grid.Column="2" Grid.Row="2" Content="Save" HorizontalAlignment="Center" VerticalAlignment="Bottom"
Command="{Binding InsertExecDefCommand}" Margin="5" >
Now my requirement is to pass selected listview items to view model through command object. I had done this using following code in FormWeek.xam.cs through SelectionChanged event as
private void OnSelectedItems(object sender, RoutedEventArgs e)
{
StringBuilder items = new StringBuilder();
foreach (string item in checkedListView.SelectedItems)
{
items.AppendFormat(item + ",");
}
string AllDays= items.ToString();
}
But please let me know how to achieve this logic through MVVM. How to get selecteditems in my view model TaskWeek.cs
After R&D and google i had done chages through RelayCommand. In OnCheckBoxCommand method foreach statement is wrong it is passing all days. I want to pass only selected listview item. Please suggest me what is wrong in OnCheckBoxCommand method.
Here are my findings;
use this code in code behind of FormWeek.xaml:
private void SelectDays(object sender, SelectionChangedEventArgs e)
{
(this.DataContext as TaskExecDefinitionViewModel).OnCheckBoxCommand(checkedListView.SelectedItems,true);
}
And in 'OnCheckBoxCommand': -
public void OnCheckBoxCommand(object obj, bool _direction)
{
try
{
if (SelectedItems == null) SelectedItems = new ObservableCollection<string>();
if (obj != null)
{
SelectedItems.Clear();
var _list = ((IList)obj).Cast<string>().ToList();
if (_direction)
{
_list.ForEach(item => SelectedItems.Add(item));
}
}
else
SelectedItems.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "TaskDefinition:OnCheckBoxCommand");
}
}
Have a nice day man.....keep going.
Hi try something like this
<StackPanel Grid.Column="1" Grid.Row="3" Margin="5">
<CheckBox x:Name="selectAll" Content="Select all" Command="{Binding CheckBoxCommand}" CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Mode=Self}}"/>
<ListView x:Name="checkedListView" SelectionMode="Extended" ItemsSource="{Binding CollectionOfDays}" SelectedItem="{Binding SelectedItems}"/>
</StackPanel>
public class MainViewModel
{
public MainViewModel()
{
CollectionOfDays = new ObservableCollection<string>();
SelectedItems = new ObservableCollection<string>();
CollectionOfDays.Add("Saturday");
CollectionOfDays.Add("Sunday");
CollectionOfDays.Add("Monday");
CollectionOfDays.Add("Tuesday");
CollectionOfDays.Add("Wednesday");
CollectionOfDays.Add("Thursday");
CollectionOfDays.Add("Friday");
}
private CommandHandler _checkBoxCommand;
public CommandHandler CheckBoxCommand
{
get
{
return _checkBoxCommand ?? (_checkBoxCommand=new CommandHandler((param)=>OnCheckBoxCommand(param)));
}
}
public ObservableCollection<string> CollectionOfDays { get; set; }
public ObservableCollection<string> SelectedItems {get;set;}
private void OnCheckBoxCommand(object obj)
{
if (obj is bool)
{
if (SelectedItems == null)
SelectedItems = new ObservableCollection<string>();
if ((bool)obj)
{
SelectedItems.Clear();
foreach (var item in CollectionOfDays)
{
SelectedItems.Add(item);
}
}
else
SelectedItems.Clear();
}
}
}
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
I hope this will give you an idea.

Silverlight Treeview inline HierarchicalDataTemplate binding issue

I have MyCollection of MyPOCO object (that has two string properties).
When I try to implement a HierarchicalDataTemplate into a treeview the binding is not working, I get the class name.
I know that if i take out the datatemplate from the control everything works fine but i am interested to see why this example is not working.
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource testVM}}">
<sdk:TreeView Margin="8,8,8,111" ItemsSource="{Binding MyCollection}">
<sdk:HierarchicalDataTemplate ItemsSource="{Binding MyPOCO}">
<sdk:HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Property1}"/>
<TextBlock Text="{Binding Property2}"/>
</StackPanel>
</DataTemplate>
</sdk:HierarchicalDataTemplate.ItemTemplate>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView>
</Grid>
Here is the ViewModel also.
namespace MyPOCProject
{
public class MyPOCO
{
private string property1;
public string Property1
{
get { return property1; }
set { property1 = value; }
}
private string property2;
public string Property2
{
get { return property2; }
set { property2 = value; }
}
public MyPOCO(string p1, string p2)
{
property1 = p1;
property2 = p2;
}
}
public class MyViewModel : INotifyPropertyChanged
{
private ObservableCollection<MyPOCO> myCollection;
public ObservableCollection<MyPOCO> MyCollection
{
get { return myCollection; }
set { myCollection = value; RaisePropertyChanged("MyCollection"); }
}
public MyViewModel()
{
MyPOCO _poco1 = new MyPOCO("aaa1", "bbb1");
MyPOCO _poco2 = new MyPOCO("aaa2", "bbb2");
MyPOCO _poco3 = new MyPOCO("aaa3", "bbb3");
MyCollection = new ObservableCollection<MyPOCO>() { _poco1, _poco2, _poco3 };
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
So what am I doing wrong?
AGAIN ... I am interested in this particular example. I want to know what's wrong with this example and why.
Thanks.
The code you posted is not hierarchical, In other words: The MyPOCO Class is not containing a property MyCollection<MYPOCO> Children.
Here is an example for the HierarchicalDataTemplate
Xaml:
<sdk:TreeView x:Name="MyTreeView"
HorizontalAlignment="Left"
ItemsSource="{Binding MyCollection}"
Width="200" Height="280">
<sdk:TreeView.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Header}"/>
<sdk:HierarchicalDataTemplate.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Header}"/>
</sdk:HierarchicalDataTemplate>
</sdk:HierarchicalDataTemplate.ItemTemplate>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>
</sdk:TreeView>
Codebehind classes:
public class MyPoco
{
public MyPoco(string header, int sampleChildrenCount)
{
this.Header = header;
this.Children = new ObservableCollection<MyPoco>();
if (sampleChildrenCount > 0)
{
for (int i = 0; i < sampleChildrenCount; i++)
{
string newHeader = String.Format("Test {0}", sampleChildrenCount * i);
var myPoco = new MyPoco(newHeader, sampleChildrenCount - 1)
this.Children.Add(myPoco);
}
}
}
public string Header { get; set; }
public ObservableCollection<MyPoco> Children { get; set; }
}
public class MyViewModel
{
public MyViewModel()
{
MyCollection = new ObservableCollection<MyPoco>();
for (int i = 0; i < 6; i++)
{
this.MyCollection.Add(new MyPoco(String.Format("Test {0}", i), 5));
}
}
public ObservableCollection<MyPoco> MyCollection { get; set; }
}
Codebehind startup:
public MainPage()
{
public MainPage()
{
InitializeComponent();
MyTreeView.DataContext = new MyViewModel();
}
}

Resources