how to insert a child item in a treeview C# WPF - c#

I want to add a child item in a TreeViewItem that was added previously. The problem with code like this:
How to insert a child node in a TreeView Control in WPF?
or with many other variations that I have tried to use like:
for (int i = 1; i <= dataTreeview.Items.Count; i++)
{
TreeViewItem tempTVI = (TreeViewItem)dataTreeview.Items.GetItemAt(i);
}
is that I get an InvalidCastException exception because items(in the other stackoverflow question) or tempTVI are strings not TreeViewItem
I don't know why this is and I ran out of ideas.
If it helps I am using Visual Studio 2015 Community in preview.
Thank you for your help.

The TreeView in WPF is an extension of ItemsControl. There are basically two ways to work with these controls, one that makes dynamically changing trees easy to manage, and one that makes completely static trees trivial to setup.
Dynamic Trees
The way TreeView was designed to be used is following the MVVM design pattern. Here is a quick example of this.
First, when working with MVVM, you always want some sort of base class for viewmodels that implements property change notification. Here is the most basic example:
internal class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then, you need a class that represents the data for a single node in the tree. For example:
internal class Node : ObservableObject
{
private ObservableCollection<Node> mChildren;
// Add all of the properties of a node here. In this example,
// all we have is a name and whether we are expanded.
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
NotifyPropertyChanged();
}
}
}
private string _name;
public bool IsExpanded
{
get { return _isExpanded; }
set
{
if (_isExpanded != value)
{
_isExpanded = value;
NotifyPropertyChanged();
}
}
}
private bool _isExpanded;
// Children are required to use this in a TreeView
public IList<Node> Children { get { return mChildren; } }
// Parent is optional. Include if you need to climb the tree
// from code. Not usually necessary.
public Node Parent { get; private set; }
public Node(Node parent = null)
{
mChildren = new ObservableCollection<Node>();
IsExpanded = true;
Parent = parent;
}
}
Now, create a viewmodel for your control with a collection of these nodes in it. In this example, the viewmodel is for the main window of the application:
internal class MainWindowVM : ObservableObject
{
private ObservableCollection<Node> mRootNodes;
public IEnumerable<Node> RootNodes { get { return mRootNodes; } }
public MainWindowVM()
{
mRootNodes = new ObservableCollection<Node>();
// Test data for example purposes
Node root = new Node() { Name = "Root" };
Node a = new Node(root) { Name = "Node A" };
root.Children.Add(a);
Node b = new Node(root) { Name = "Node B" };
root.Children.Add(b);
Node c = new Node(b) { Name = "Node C" };
b.Children.Add(c);
Node d = new Node(b) { Name = "Node D" };
b.Children.Add(d);
Node e = new Node(root) { Name = "Node E" };
root.Children.Add(e);
mRootNodes.Add(root);
}
}
Finally, create the TreeView instance and set it up to use your data. In this example, the TreeView is the only thing in the main application window:
<Window x:Class="WpfTreeViewExample.MainWindow"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfTreeViewExample"
SizeToContent="WidthAndHeight"
Title="MainWindow">
<Window.DataContext>
<local:MainWindowVM />
</Window.DataContext>
<TreeView
Margin="10"
ItemsSource="{Binding RootNodes}">
<ItemsControl.ItemContainerStyle>
<Style
TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
<!-- Could also put IsSelected here if we needed it in our Node class -->
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<HierarchicalDataTemplate
DataType="{x:Type local:Node}"
ItemsSource="{Binding Children}">
<!-- Can build any view we want here to be used for each node -->
<!-- Simply displaying the name in a text block for this example -->
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</ItemsControl.ItemTemplate>
</TreeView>
</Window>
Once you have this setup, all you have to do from now on is manipulate the data in your viewmodel, and the TreeView will automatically update to reflect those changes. This way, you never need to manipulate the control directly.
Here is the resulting view:
Static Trees
If the entire tree is known ahead of time and will never change, you can set it up pretty simply like this:
<TreeView
x:Name="mTreeView"
Margin="10">
<TreeViewItem Header="Root">
<TreeViewItem Header="Node A" />
<TreeViewItem Header="Node B">
<TreeViewItem Header="Node C" />
<TreeViewItem Header="Node D" />
</TreeViewItem>
<TreeViewItem Header="Node E" />
</TreeViewItem>
</TreeView>
The problem with this approach is that when you want to modify the tree programmatically, it becomes hard to manage because you have to deal with the TreeView itself. However, it is doable from a code-behind. For example, if I want to add a new child node under "Node C" called "New Node", I could do something like this:
((TreeViewItem)((TreeViewItem)((TreeViewItem)mTreeView.Items[0]).Items[1]).Items[0]).Items.Add(new TreeViewItem() { Header = "New Node" });
Working this way gets messy though. Since we don't have a parallel representation of the tree in data, we have to keep accessing things through the control and casting them.
Some Other Setup
Looking at your question, it looks like you are not following either of these approaches, but instead have a TreeView that is setup basically like this:
<TreeView>
<sys:String>Node A</sys:String>
<sys:String>Node B</sys:String>
</TreeView>
So, you have a TreeView full of strings. Internally, an ItemsControl can take any object and wrap it in an item container. TreeView will wrap those strings in TreeViewItem instances. However, the items are still stored as strings, and accessing TreeView.Items will return the strings that you added.
Getting the TreeViewItem associated with an arbitrary item in a TreeView is actually fairly difficult because you have to get the containers for each item at the root level, then dig into each of those and get containers for their items, and so on all the way through the tree until you find the item you are looking for.
You can find an example for how to lookup item containers here. Note that you cannot use virtualization in your TreeView in order for this to work reliably. Also, I would recommend against working this way because you are making things harder on yourself.

You are getting String because that is what the source of the TreeView must have been bound to.
Using this method allows you to iterate over the items and retrieve the TreeViewItem containers that they are inside:
List<TreeViewItem> GetChildren(TreeViewItem parent)
{
List<TreeViewItem> children = new List<TreeViewItem>();
if (parent != null)
{
foreach (var item in parent.Items)
{
TreeViewItem child = item as TreeViewItem;
if (child == null)
{
child = parent.ItemContainerGenerator.ContainerFromItem(child) as TreeViewItem;
}
children.Add(child);
}
}
return children;
}
Please notice that they check if the TreeViewItem is null after casting it. This is good practice as it prevents the null reference exception from crashing your application if something does happen to go wrong.
source: https://social.msdn.microsoft.com/Forums/vstudio/en-US/595f0c84-01e7-4534-b73b-704b41713fd5/traversing-the-children-of-a-treeviewitem

Maybe you forgot the tags?
If you have the following in your xaml file:
<TreeView x:Name="MyTreeView">
<TreeViewItem>Hello</TreeViewItem>
World
</TreeView>
And the following in the code-behind:
var a = MyTreeView.Items.GetItemAt(0) as string;
var b = MyTreeView.Items.GetItemAt(0) as TreeViewItem;
var c = MyTreeView.Items.GetItemAt(1) as string;
var d = MyTreeView.Items.GetItemAt(1) as TreeViewItem;
Variables a and d will be null whereas b will be a TreeViewItem and c will be a string.

Related

Bridge IEnumerable collection binding it to TreeView in WPF

I have been looking to find the solution to this problem but still, after so much research, I am unable to figure out an elegant solution. Finally, I have decided to ask it here to get an experts opinion.
It's a WPF application where I have created my domain/model classes like:
public abstract class Node : Entity
{
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
public Node Parent { get; set; }
private List<Node> _children = new List<Node>();
public IEnumerable<Node> Children => _children.AsEnumerable();
public void AddChild(Node node)
{
_children.Add(node);
}
public void RemoveChild(Node node)
{
_children.Remove(node);
}
public void MoveUp(Node node)
{
var index = _children.IndexOf(node);
Move(index, index - 1);
}
public void MoveDown(Node node)
{
var index = _children.IndexOf(node);
Move(index, index + 1);
}
}
According to this domain, Node class has a parent-child relationship.
The important point to note here is Children collection type is exposed as IEnumerable to encapsulate it to avoid undesired changes to my collection. I want to bind this collection to a TreeView control to show N-level of the hierarchy.
<HierarchicalDataTemplate x:Key="ContainerTemplate"
DataType="{x:Type fsx:Node}"
ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
<fsx:TreeViewTemplateSelector x:Key="TreeViewTemplateSelector"
ContainerTemplate="{StaticResource ContainerTemplate}" />
<TreeView x:Name="TreeViewNodes"
ItemsSource="{Binding Nodes}"
ItemTemplateSelector="{StaticResource TreeViewTemplateSelector}">
</TreeView>
Imagine, Nodes that is bound to TreeView ItemSource property is ObservableCollection in ViewModel which is getting the data from Model.
I want to allow UI operations like adding and removing nodes and moving them up and down and correspondingly I want to update those operations in my domain object. Now the problem is that since my collection is not ObservableCollection, any operations I am performing is not reflected in UI.
Question is how to make it all work instantly showing the operation result on UI as well as updating the domain behind the scene effectively?
Note: I will update the question to provide more details if required!

Binding Element to Property from Inherited Data Context

I have a WPF control pane with sixteen of the same child control containing a combobox that needs to be bound to a list in the Parent Control code behind. I was really struggling to get this list to bind until I found this: Binding objects defined in code-behind.
Setting DataContext="{Binding RelativeSource={RelativeSource Self}}" on the Parent Control allowed me to bind the combobox on the child control directly.
The problem is that now I want to create a Data Template to display the list items properly, but nothing I put in the Binding or Relative Source Displays anything.
ControlPane.xaml
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlPane"
x:Name="CtrlPaneWpf"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
ControlPane.xaml.cs
public class TwoStringClass
{
public string string1;
public string colorHex;
}
public ObservableCollection<TwoStringClass> TwoStringClass1
{
get
{
ObservableCollection<TwoStringClass> cmbclrs = new ObservableCollection<TwoStringClass>();
cmbclrs.Add(new TwoStringClass() { string1 = "This", colorHex = "#FF0000" });
cmbclrs.Add(new TwoStringClass() { string1 = "That", colorHex = "#FF352E2" });
cmbclrs.Add(new TwoStringClass() { string1 = "The Other", colorHex = "#FFF4F612" });
return cmbclrs;
}
}
ChildControl.xaml
<UserControl
x:Name="ChildControl"
>
<ComboBox x:Name="cmbFontColor" ItemsSource="{Binding TwoStringClass1}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding string1}" />
<Rectangle Fill="{Binding colorHex}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</UserControl>
I know the Binding is Working because I get the correct number of (blank) items in the Combobox and can see the class name if I remove the ItemTemplate.
I can't figure out for the life of me why binding to the property name isn't working here as it does when the list comes from a control's own code behind.
There must be some other information I need to add to the TextBlock binding, but no matter what DataContext or RelativeSource I try, I always get blank items.
Data binding in WPF works with public properties only, not with fields. Your item class should look like this:
public class TwoStringClass
{
public string string1 { get; set; }
public string colorHex { get; set; }
}
That said, there are widely accepted naming convention, according to which you should use Pascal case for property names, e.g. String1 and ColorHex.
I believe the answer to your question is the same as the answer to a question I posted recently, which was answered by StewBob. Here is my slightly modified version of his answer, which should also fix the issue you are having.
You can see my original thread here: WPF ListBox with CheckBox data template - Binding Content property of Checkbox not working
I see you added "This", "That", and "The Other" as your data source, presumably for simplicity in posting this question to SO. Please be aware that if your true underlying data source can change, when doing DataBinding, your class needs to implement INotifyPropertyChanged for the data to properly display in the UI. An example:
public class TwoStringClass: INotifyPropertyChanged
{
private string _String1;
private string _ColorHex;
public string String1
{
get
{
return _String1;
}
set
{
if (value != _String1)
{
_String1 = value;
NotifyPropertyChanged("String1");
}
}
}
public string ColorHex
{
get
{
return _ColorHex;
}
set
{
if (value != _ColorHex)
{
_ColorHex = value;
NotifyPropertyChanged("ColorHex");
}
}
}
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
This shows the class, two properties, and the needed event and method for implementing INotifyPropertyChanged.

get parent-note in treeview when the child-items are the same object

i have a TreeView with same in xaml createt TreeViewItems. And one note has a ObservableCollection as ItemSource. This works like a Charm. But now i want same Notes to every item of the list (for better organization). So i do this:
This is my HierarchicalDataTemplate for the liste
<HierarchicalDataTemplate DataType="{x:Type classes:Connection}" ItemsSource="{Binding Source={StaticResource ConnectionChilds}}" >
<TextBlock Text="{Binding DisplayName}" />
</HierarchicalDataTemplate>
And the ItemsSource:
<collections:ArrayList x:Key="ConnectionChilds">
<classes:TreeItemObject ItemsSourcePath="Child1" />
<classes:TreeItemObject ItemsSourcePath="Child2" />
<classes:TreeItemObject ItemsSourcePath="Child3" />
</collections:ArrayList>
TreeItemObject is a simple Class:
public class TreeItemObject
{
public string ItemsSourcePath { get; set; }
}
And last but not least HierarchicalDataTemplate for TreeItemObject:
<DataTemplate DataType="{x:Type classes:TreeItemObject}">
<TextBlock Margin="5,0" Text="{Binding Path=ItemsSourcePath}"/>
</DataTemplate>
Looked like this
Connection 1
Child1
Child2
Child3
Connection 2
Child1
Child2
Child3
Connection 3
Child1
Child2
Child3
Works perfekt. But now if i select "Connection 2\Child3" i got the same object like "Connection 1\Child3" or "Connection 3\Child3". Ok make sense because based on same object. With that situation i have no chance to find out the parent-note on OnSelectedItemChanged.
Because if i search with this extension-Class. I only get the first expanded Connection-Note.
http://social.msdn.microsoft.com/Forums/silverlight/en-US/84cd3a27-6b17-48e6-8f8a-e5737601fdac/treeviewitemcontainergeneratorcontainerfromitem-returns-null?forum=silverlightnet
Is there a way to find the real parent in the TreeView?
I personally do not like the idea of creating clones within a converter but I do not know the full scope of your problem. So working with what you have presented here, we can achieve the assignment of a parent to each TreeItemObject via a MultiValueConverter.
WPF has an awesome feature called MultiBinding. It processes 1 or more source values into a single target. To do this, it needs a multivalue converter.
So, change the TreeItemObject to
public class TreeItemObject
{
public string ItemsSourcePath { get; set; }
public WeakReference Parent { get; set; }
}
The hierarchicalDataTemplate for the Connection type would become
<HierarchicalDataTemplate DataType="{x:Type classes:Connection}">
<HierarchicalDataTemplate.ItemsSource>
<MultiBinding Converter="{StaticResource items2Clones}">
<Binding Source="{StaticResource ConnectionChilds}" />
<Binding />
</MultiBinding>
</HierarchicalDataTemplate.ItemsSource>
<TextBlock Text="{Binding DisplayName}" />
</HierarchicalDataTemplate>
Based on the above binding, to set the parent in the converter, the Convert method in your convert will be along the lines
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var destinationItems = new Collection<TreeItemObject>();
var items = values[0] as Collection<TreeItemObject>;
var parent = values[1] as Connection;
// null checks are required here for items and parent
foreach (var item in items)
{
var destinationItem = item.Clone(); // Assumed extension method
destinationItem.Parent = new WeakReference(parent);
destinationItems.Add(destinationItem);
}
return destinationItems;
}
Finally, the SelectedItemChanged event handler would be something like
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var item = (TreeItemObject)e.NewValue;
if ((item != null) && (item.Parent != null) && (item.Parent.IsAlive))
{
// do stuff - Console.WriteLine(((Connection)item.Parent.Target).DisplayName);
}
}
I have removed exception management and some null checking for brevity.
I hope this helps
I think your only choice is to clone your children before you add them to the TreeView, allowing at least a binary difference between the child nodes.
If you do this, instead of handling the OnSelectedItemChanged event and traversing the object graph, add a WeakReference of the parent to each of its children. This will allow you to immediately reference the parent from the child and also allow .Net to clean up the object graph correctly.
An example of using a WeakReference property from a SelectedItemChanged event handler is as follows
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var treeView = sender as TreeView;
var item = treeView.SelectedItem as TreeItemObject;
if (item.Parent.IsAlive)
{
var parent = item.Parent.Target;
}
}
I have removed exception management and null checking for brevity.
I hope this helps.
It's difficult to get the parent from the treeView item so what i did is that, i had a member property of the parent of the parent type which holds the reference to the parent as below
public class FileSystem :NotifyChange, IEnumerable
{
#region Private members
private ObservableCollection<FileSystem> subDirectoriesField;
#endregion
#region Public properties
/// <summary>
/// Gets and sets all the Files in the current folder
/// </summary>
public ObservableCollection<FileSystem> SubDirectories
{
get
{
return subDirectoriesField;
}
set
{
if (subDirectoriesField != value)
{
subDirectoriesField = value;
RaisePropertyChanged("SubDirectories");
}
}
}
/// <summary>
/// Gets or sets name of the file system
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// Gets or sets full path of the file system
/// </summary>
public string FullPath
{
get;
set;
}
/// <summary>
/// object of parent, null if the current node is root
/// </summary>
public FileSystem Parent
{
get;
set;
}
public FileSystem(string fullPath, FileSystem parent)
{
Name = fullPath != null ? fullPath.Split(new char[] { System.IO.Path.DirectorySeparatorChar },
StringSplitOptions.RemoveEmptyEntries).Last()
FullPath = fullPath;
Parent = parent;
AddSubDirectories(fullPath);
}
public IEnumerator GetEnumerator()
{
return SubDirectories.GetEnumerator();
}
private void AddSubDirectories(string fullPath)
{
string[] subDirectories = Directory.GetDirectories(fullPath);
SubDirectories = new ObservableCollection<FileSystem>();
foreach (string directory in subDirectories)
{
SubDirectories.Add(new FileSystem(directory, this));
}
}
}
And my viewModel is as below
public class ViewModel:NotifyChange
{
private ObservableCollection<FileSystem> directories;
public ObservableCollection<FileSystem> Directories
{
get
{
return directoriesField;
}
set
{
directoriesField = value;
RaisePropertyChanged("Directories");
}
}
public ViewModel()
{
//The below code has to be moved to thread for better user expericen since when UI is loaded it might not respond for some time since it is looping through all the drives and it;s directories
Directories=new ObservableCollection<FileSystem>();
Directories.Add(new FileSystem("C:\\", null);
Directories.Add(new FileSystem("D:\\", null);
Directories.Add(new FileSystem("E:\\", null);
}
}
Since each child knows it;s parent now you can traverse back, root node parent will be null
Xmal will have the following
<TreeView Grid.Row="1" Background="Transparent" ItemsSource="{Binding Directories}" Margin="0,10,0,0" Name="FolderListTreeView"
Height="Auto" HorizontalAlignment="Stretch" Width="300" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:FileSystem}" ItemsSource="{Binding SubDirectories}">
<Label Content="{Binding Path= Name}" Name="NodeLabel" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
Hope this helps you

WPF - Bound treeview not updating root items

I'm using a WPF TreeView control, which I've bound to a simple tree structure based on ObservableCollections. Here's the XAML:
<TreeView Name="tree" Grid.Row="0">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Text}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
And the tree structure:
public class Node : IEnumerable {
private string text;
private ObservableCollection<Node> children;
public string Text { get { return text; } }
public ObservableCollection<Node> Children { get { return children; } }
public Node(string text, params string[] items){
this.text = text;
children = new ObservableCollection<Node>();
foreach (string item in items)
children.Add(new Node(item));
}
public IEnumerator GetEnumerator() {
for (int i = 0; i < children.Count; i++)
yield return children[i];
}
}
I set the ItemsSource of this tree to be the root of my tree structure, and the children of that become root-level items in the tree (just as I want):
private Node root;
root = new Node("Animals");
for(int i=0;i<3;i++)
root.Children.Add(new Node("Mammals", "Dogs", "Bears"));
tree.ItemsSource = root;
I can add new children to the various non-root nodes of my tree structure, and they appear in the TreeView right where they should.
root.Children[0].Children.Add(new Node("Cats", "Lions", "Tigers"));
But, if I add a child to the root node:
root.Children.Add(new Node("Lizards", "Skinks", "Geckos"));
The item does not appear, and nothing I've tried (such as setting the ItemsSource to null and then back again) has caused it to appear.
If I add the lizards before setting the ItemsSource, they show up, but not if I add them afterwards.
Any ideas?
You are setting ItemsSource = root which happens to implement IEnumerable but is not in and of itself observable. Even though you have a Children property which is observable, that's not what you're binding the TreeView to so the TreeView doesn't have any way of listening to changes that occur through the Children property.
I would drop IEnumerable from the Node class altogether. Then set treeView.ItemsSource = root.Children;
if 'root' is an ObservableCollection your treeview will update. is 'root' an observable collection, or is root a node that is in an observable collection? seeing your binding for the items source would help to answer this question. as you are assigning it in code you might just be setting it to be a single element, not a collection

Problem with TreeView in SilverLight

I have the following class structure:
class Organization
{
string Name;
List<User> users;
List<Organization> Children;
}
class User
{
string Name;
}
I cannot modify these classes.
I need to display all the information about organizations and users in one TreeView control. I.e., organization nodes should contain suborganization and user nodes.
The question is how can I do this having no CompositeCollections or Multibindings in Silverlight?
The tricky part of this solution is having to deal with two collections underneath each node and TreeView's HierarchicalDataTemplate only supports binding to a single ItemsSource.
One option is to create a ViewModel that merges the collections into a single class that represents an entry in the TreeView that you can then bind to inside your HierarchicalDataTemplate.
First I created my ViewModel class:
public class TreeViewEntry
{
public string Name { get; set; }
public IEnumerable<TreeViewEntry> Children { get; set; }
public object Model { get; set; }
}
Then I used a function, some Linq and some recursion to pull all the objects into a single collection:
private IEnumerable<TreeViewEntry> OrganizationsToTreeViewEntries(IEnumerable<Organization> orgs)
{
return (from o in orgs
select new TreeViewEntry
{
Name = o.Name,
Model = o,
Children = (from u in o.Users
select new TreeViewEntry
{
Name = u.Name,
Model = u
}
).Concat(OrganizationsToTreeViewEntries(o.Children))
});
}
public MainPage()
{
InitializeComponent();
var items = OrganizationsToTreeViewEntries(existingOrganizationData);
OrgTree.ItemsSource = items;
}
Now that I have a merged ItemsSource it's easy to style my HierarchicalDataTemplate:
<UserControl.Resources>
<common:HierarchicalDataTemplate x:Key="OrgTemplate" ItemsSource="{Binding Children}">
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</common:HierarchicalDataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
<controls:TreeView x:Name="OrgTree" HorizontalAlignment="Left" Margin="8,8,0,8" Width="225" ItemTemplate="{StaticResource OrgTemplate}" />
</Grid>
You can use a ValueConverter to tweaks things like FontWeight if you want to adjust the visual style of certains elements (for example in my testing I created a ValueConverter on FontWeight that was bound to the Model property of TreeViewEntry).
I misread the question - I don't know of a way for the SL tree to display both the Children property and the Users property as child nodes. You may want to create a wrapper class with an AllChildren property that returns Users and Organizations in the same collection. The SL tree's HierarchialDataTemplate has a single property called ItemsSource that should be bound to a single child collection. Sorry I couldn't be more help - I'd delete this answer but I don't see a way to do that.

Categories

Resources