TreeView.ItemContainerGenerator.ContainerFromItem returns null
-
Wednesday, January 14, 2009 7:30 AM
Hi, Geeks!
I cannot understand why the TreeView.ItemContainerGenerator.ContainerFromItem method always returns null. I am calling this method after the tree has been totally initialized and already contains some value.
here is the code:
Public Sub CollapseTree() If sideTreeView.Items.Count > 0 Then For Each tItem In sideTreeView.Items(0).Children Dim treeItem As TreeViewItem = TryCast(sideTreeView.ItemContainerGenerator.ContainerFromItem(tItem), TreeViewItem) treeItem.IsExpanded = False Next End If End Sub
tItem is my custom hierarchical object. Please, tell me the reason for Null referenced object exception returned for above code.
All Replies
-
Wednesday, January 14, 2009 8:26 PM
Hello? Is there any note for post above?
-
Friday, January 16, 2009 8:21 PM
I hate this "feature", but we had to keep ItemContainerGenerator compatible with how WPF's one works.
ItemContainerGenerator is hierarchly aware. Meaning that the TreeView.ItemContainerGenerator will only know direct children of the TreeView. and the TreeViewItem.ItemContainerGenerator will only knows it's own direct children.
So essentially a TreeView has as many ItemContainerGenerators as it has TreeViewItems+1. And again, each of these ItemContainerGenerators only knows about the children of the instance it belongs to.Your code snippet is looking at the Children of the 1st TreeViewItem, but instead of querying the 1st TreeViewItem's ItemContainerGenerator is querying the TreeView's ItemContainerGenerator.
So this change should fix the issue you're seeing:
Public Sub CollapseTree()
If sideTreeView.Items.Count > 0 Then
For Each tItem In sideTreeView.Items(0).Children
Dim treeItem As TreeViewItem = TryCast(sideTreeView.Items(0).ItemContainerGenerator.ContainerFromItem(tItem), TreeViewItem)
treeItem.IsExpanded = False
Next
End If
End SubHowever, You probably saying to yourself "Well, this sucks, they know it sucks, I wanna die". Well, don't.
We're looking intensively as to where we can improve on the existing WPF TreeView without breaking WPF Compat.
You can read more about these efforts @ http://blogs.msdn.com/sburke/archive/2008/11/11/wpf-and-silverlight-toolkit-compatibility.aspxIn the meanwhile, use these 2 extension methods:
public static class TreeViewExtensions
{
public static TreeViewItem ContainerFromItem(this TreeView treeView, object item)
{
TreeViewItem containerThatMightContainItem = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
else
return ContainerFromItem(treeView.ItemContainerGenerator, treeView.Items, item);
}
private static TreeViewItem ContainerFromItem(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, object item)
{
foreach (object curChildItem in itemCollection)
{
TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem);
TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
TreeViewItem recursionResult = ContainerFromItem(parentContainer.ItemContainerGenerator, parentContainer.Items, item);
if (recursionResult != null)
return recursionResult;
}
return null;
}
public static object ItemFromContainer(this TreeView treeView, TreeViewItem container)
{
TreeViewItem itemThatMightBelongToContainer = (TreeViewItem)treeView.ItemContainerGenerator.ItemFromContainer(container);
if (itemThatMightBelongToContainer != null)
return itemThatMightBelongToContainer;
else
return ItemFromContainer(treeView.ItemContainerGenerator, treeView.Items, container);
}
private static object ItemFromContainer(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, TreeViewItem container)
{
foreach (object curChildItem in itemCollection)
{
TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem);
TreeViewItem itemThatMightBelongToContainer = (TreeViewItem)parentContainer.ItemContainerGenerator.ItemFromContainer(container);
if (itemThatMightBelongToContainer != null)
return itemThatMightBelongToContainer;
TreeViewItem recursionResult = ItemFromContainer(parentContainer.ItemContainerGenerator, parentContainer.Items, container) as TreeViewItem;
if (recursionResult != null)
return recursionResult;
}
return null;
}
}
And your code snippet would even look better:
Public Sub CollapseTree()
If sideTreeView.Items.Count > 0 Then
For Each tItem In sideTreeView.Items(0).Children
Dim treeItem As TreeViewItem = TryCast(sideTreeView.ContainerFromItem(tItem), TreeViewItem)
treeItem.IsExpanded = False
Next
End If
End SubHopefully, this helps.
Sincerely,
-
Tuesday, January 20, 2009 3:44 AMThank you for help. The thing that I have actually done is I extended the TreeViewItem object with additional properties and methods that my custom hierarchical object had, and used that class while building my treeview dynamically. That works fine for me.
-
Wednesday, April 08, 2009 9:34 AM
Hi Justin,
I am trying to use your suggestion to expand the root items in a treeview:
Public Sub CollapseTree()
If sideTreeView.Items.Count > 0 Then
For Each tItem In sideTreeView.Items(0).Children
Dim treeItem As TreeViewItem = TryCast(sideTreeView.ContainerFromItem(tItem), TreeViewItem)
treeItem.IsExpanded = False
Next
End If
End SubMy c# version is this:
foreach (myItemType pcItem in CategoryTreeView.Items) { TreeViewItem tvi = (TreeViewItem)CategoryTreeView.ContainerFromItem(pcItem); tvi.IsExpanded = true; }
However, at runtime, I get an exception in the helper class you provided above at this line:
TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
parentContainer seems to be null.
What am I missing? I spent ages on investigating this... :(
vitya
-
Wednesday, April 22, 2009 4:02 AM
same issue with Vitya~~
My toolkit is "Microsoft Silverlight 3 Toolkit March 2009"
-
Monday, May 11, 2009 8:16 AM
Hello Justin...
Im getting a null Exception in this line:
1 private static TreeViewItem ContainerFromItem(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, object item) 2 { 3 foreach (object curChildItem in itemCollection) 4 { 5 TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem); 6 //parentContainer <-- is now null !=?!?!? 7 8 TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item); 9 if (containerThatMightContainItem != null) 10 return containerThatMightContainItem; 11 TreeViewItem recursionResult = ContainerFromItem(parentContainer.ItemContainerGenerator, parentContainer.Items, item); 12 if (recursionResult != null) 13 return recursionResult; 14 } 15 return null; 16 }
parentContainer is null
-
Monday, May 11, 2009 8:32 PM
Hi,
Sorry about that, I forogt to account for virtualized TreeViewItems. My bad.
public static class TreeViewExtensions
{
public static TreeViewItem ContainerFromItem(this TreeView treeView, object item)
{
TreeViewItem containerThatMightContainItem = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
else
return ContainerFromItem(treeView.ItemContainerGenerator, treeView.Items, item);
}
private static TreeViewItem ContainerFromItem(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, object item)
{
foreach (object curChildItem in itemCollection)
{
TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem);
if (parentContainer == null)
return null;
TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
TreeViewItem recursionResult = ContainerFromItem(parentContainer.ItemContainerGenerator, parentContainer.Items, item);
if (recursionResult != null)
return recursionResult;
}
return null;
}
public static object ItemFromContainer(this TreeView treeView, TreeViewItem container)
{
TreeViewItem itemThatMightBelongToContainer = (TreeViewItem)treeView.ItemContainerGenerator.ItemFromContainer(container);
if (itemThatMightBelongToContainer != null)
return itemThatMightBelongToContainer;
else
return ItemFromContainer(treeView.ItemContainerGenerator, treeView.Items, container);
}
private static object ItemFromContainer(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, TreeViewItem container)
{
foreach (object curChildItem in itemCollection)
{
TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem);
if (parentContainer == null)
return null;
TreeViewItem itemThatMightBelongToContainer = (TreeViewItem)parentContainer.ItemContainerGenerator.ItemFromContainer(container);
if (itemThatMightBelongToContainer != null)
return itemThatMightBelongToContainer;
TreeViewItem recursionResult = ItemFromContainer(parentContainer.ItemContainerGenerator, parentContainer.Items, container) as TreeViewItem;
if (recursionResult != null)
return recursionResult;
}
return null;
}
}
-
Thursday, July 30, 2009 11:27 AM
Still doesn't work. Always returns null. I can't believe how badly Microsoft has obfuscated this control. I just want to iterate the friggin nodes and set expanded to True where appropriate.
-
Thursday, July 30, 2009 12:16 PMdo it like me...
build your own god damn TreeView...
i ensure you that:
- it works as you want it to
- its cleaner
- it looks like you want it to
- it handle mouse gestures much better !
maybe i should publish my tree somewhere...
you can see it on http://87.54.35.102/planit (test / test)
it doesn't fold, but that would take me 10 min to do ;-)
-
Monday, September 07, 2009 3:30 AM
JustinAngel's method is great . But before you use it ,make sure that the treeviewitem has generated,or ,null is return .
example : treeview.ExpandAll();
treeview.UpdateLayout();then try to find .
-
Friday, September 18, 2009 9:13 AMHello, I don't know if anyone keeps having this problem, but I was and it seems I solve it. It seems you need to call method ExpandAndSelectNode(string idOrWhatever) in asynchronous way. So if you call it normally, you will get NULL from ContainerFromItem(), but if you call it like this: this.Dispatcher.BeginInvoke(()=>ExpandAndSelectNode(string idOrWhatever)); it will work! At least in my case this solved the "null-returning-problem". Please correct me if I am telling some nonsenses...
-
Wednesday, December 02, 2009 12:41 PM
Had the same problem; yeah looks like a timing issue.
Fixed it by moving the code into the 'Loaded' event handler, i.e. instead of:
MyTreeViewControl.ItemsSource = data; // code that makes calls to ItemContainerGenerator.ContainerFromItem ...I use:
MyTreeViewControl.ItemsSource = data; MyTreeViewControl.Loaded += (s, e) => { // code that makes calls to ItemContainerGenerator.ContainerFromItem ... };HTH
-
Friday, July 16, 2010 5:09 AM
I have tried every possible solution given here but still getting null for level 2 hierarchical childs.. The Loaded event is not getting invoked at all
-
Friday, July 16, 2010 5:18 AM
make your own tree
its worth the effort !
-
Friday, July 16, 2010 5:26 AM
brother anuger u want to autoselect childitem in treeviewitem ?
-
Friday, July 16, 2010 6:42 AM
XAML
<sdk:HierarchicalDataTemplate x:Key="ChildTemplate" ItemsSource="{Binding Path=Children}"> <TextBlock Text="{Binding Path=Name}"/> </sdk:HierarchicalDataTemplate> <sdk:TreeView ItemsSource="{Binding}" x:Name="myTreeView" ItemTemplate="{StaticResource ChildTemplate}" Grid.Row="1"/>CS Part
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); //PolluteTreeFunction myTreeView.DataContext = <polluted dataTree collection>; } } public class DataTree { private ObservableCollection<DataTree> _children; public string Name { get; set; } public ObservableCollection<DataTree> Children { get { return _children; } set { _children = value; } } public DataTree(string name, ObservableCollection<DataTree> children) { Name = name; Children = children; } }Now I want a ExpandAll() kinda function.
public void ExpandAll() { DataTree dataNode = (myTreeView.DataContext as ObservableCollection<DataTree>)[0]; TreeViewItem treeViewItem = myTreeView.ItemContainerGenerator.ContainerFromItem(dataNode) as TreeViewItem; treeViewItem.IsExpanded = true; foreach (DataTree childDataNode in dataNode.Children) { Expand(childDataNode, treeViewItem); } } public void Expand(DataTree dataNode, TreeViewItem parentNode) { if (dataNode.Children != null) { TreeViewItem treeViewItem = parentNode.ItemContainerGenerator.ContainerFromItem(dataNode) as TreeViewItem; treeViewItem.IsExpanded = true; foreach (DataTree childDataNode in dataNode.Children) { Expand(childDataNode, treeViewItem); } } }But treeViewItem is getting null in Expand() function.. I have tried the Loaded, Dispatcher, UpdateLayout methods.. but none works
@Montago I already have made a custom TreeViewItem and want to check the performance difference between the ViewModel approach and CustomTreeNode approach
-
Friday, July 16, 2010 7:07 AM
@Montago I already have made a custom TreeViewItem and want to check the performance difference between the ViewModel approach and CustomTreeNode approach
regardless of the performance, i think you should throw the SL.NET TreeView in the trash and create your own TreeView
there are so many fuzzy-weird-F'ed Up problems using the treeview that i simply never use it for advanced tasks anymore.
such as a simple task of getting the event when selecting or clicking on a node does a whole lot of weird things.... i don't know if any of the issues has been solved in SL4 - i haven't checked - but i fear they haven't.... otherwize you wouldn't be posting, right ??
even styling of a treeview is hard (unless you are a Blend-Geek) - styling your own tree takes like 30 minutes compared to a whole day of styling a generic TreeView :-(
-
Friday, October 22, 2010 7:25 AM
Hi Jumbo,
can you provide your full source code plz....i am also facing same issue..
Actually i am trying to expand the parent node. can u pla help..
-
Saturday, October 23, 2010 3:02 PM
Hi JustinAngel,
I am creating a silverlight application. I am trying to expand the treevire items selectively on page load..
meaning..i am pasing some value in querystring paramater. if parameter value exists as a child of any treeview item then it has to expand its parent node.
i tried in button click event and am able to achive this.
How to use the extension methos that you have mentioned in your blog? Can you please suggest me how can i expand the treeview node on page load?
could you please provide sample example?
thanks,
-
Tuesday, October 26, 2010 5:07 PM
Well the solution is much simpler than anyone has ever thought. Just set the IsExpanded property of the newly inserted node to true and that would take away all the pain :)
-Kuntal Kishore -
Wednesday, October 27, 2010 2:44 AM
MUHAHAHAHAHAHAHA AAHAHAHAHAH !!! HAHAHAHAHA
if only it was that simple !
The scenario is:
you click on a node to select it
the selectednode_changed event is fired
the object: sender = your bound object, NOT your TreeViewItem
so now you need to find the real TreeViewItem - which is the reason why we have this thread.
-
Tuesday, November 02, 2010 8:23 AM
Hi all,
thanks for your reply. I figured out the solution for my problem.
I caled used LayoutUpdated event to expand the specific treeview node on page load.
MyTreeView.LayoutUpdated +=
new EventHandler
(MyTreeView_LayoutUpdated);
-
Wednesday, March 02, 2011 9:26 AM
none of above solutions helped me out, I am still unable to expand a single tree node on 4th level...
instead of ObservableCollection<> i m using List<> does it make any differece ? or I should forcfully use ObservableCollection<> ?
-
Monday, March 14, 2011 4:02 AM
any one please help
-
Tuesday, February 21, 2012 11:26 PM
How to find the TreeViewItem when the tree view is collapsed.

