Answered by:
Preselecting a Treevieitem on usercontrol load

Question
-
Hi,
I have a field selection wizard usercontrol in which I have a Treeview which gets populated using some Webservice. The user selects an item from the treeview and closes the wizard. Next time when the user launches this wizard, the treeview item need to be preselected on usercontrol load or any other appropriate event in this case. I bind the itemsource of the treeview in the Usercontrol loaded event. I invoke the preselection method as the last statement in the Loaded event. In the preselection method, I tried itereating through the tree for finding the item recursively, but this did not yield any result. In my node search method I retreive the child TreeviewItem by calling the current node's
ItemContainerGenerator.ContainerFromItem(item) method. But this yields null when invoked at this point of time. To verify, I put another button in the usercontrol just for invoking the preselection logic to see if it works , then it worked just fine.
My thinking regarding the issue is that the Treeview items are not yet generated when I invoke the ItemContainerGenerator.ContainerFromItem(item) during the usercontrol Loaded event. I did not not find any help on this anywhere. Iam not sure if If Iam trying to do the right thing here. Anybody has any clue what I need to do to get this to work??
Thanks in Advance
Siva
Friday, February 1, 2008 6:17 PM
Answers
-
This is because the TreeViewItem is not intialized, so we are unable to get its container. The following example shows how to do this. I hope this helps.
Code Snippetnamespace ForumProjects
{
public partial class MainWindow : Window
{
public MainWindow()
{
this.Persons = new List<Person>()
{
new Person(){Name="A1"},
new Person(){Name="A2"},
};
this.Persons[0].Children.Add(new Person() { Name = "B1" });
this.Persons[0].Children.Add(new Person() { Name = "B2" });
this.Persons[1].Children.Add(new Person() { Name = "B3" });
this.Persons[1].Children.Add(new Person() { Name = "B4" });
this.Persons[0].Children[0].Children.Add(new Person() { Name = "C1" });
this.Persons[0].Children[0].Children.Add(new Person() { Name = "C2" });
this.Persons[0].Children[1].Children.Add(new Person() { Name = "C3" });
this.Persons[0].Children[1].Children.Add(new Person() { Name = "C4" });
this.Persons[1].Children[0].Children.Add(new Person() { Name = "C5" });
this.Persons[1].Children[0].Children.Add(new Person() { Name = "C6" });
this.Persons[1].Children[1].Children.Add(new Person() { Name = "C7" });
this.Persons[1].Children[1].Children.Add(new Person() { Name = "C8" });
this.toSelectPerson = this.Persons[1].Children[0].Children[1];
InitializeComponent();
}
public List<Person> Persons { get; private set; }
private Person toSelectPerson;
private LinkedList<Person> linkedPersons;
private void TreeView_Loaded(object sender, RoutedEventArgs e)
{
this.linkedPersons = new LinkedList<Person>();
this.linkedPersons.AddFirst(this.toSelectPerson);
FillLinkedPersons(this.toSelectPerson.Parent);
ExpandAndSelect(this.linkedPersons.First, this.PersonList.ItemContainerGenerator);
}
private void FillLinkedPersons(Person person)
{
if (person != null)
{
this.linkedPersons.AddBefore(this.linkedPersons.First, person);
FillLinkedPersons(person.Parent);
}
}
private void ExpandAndSelect(LinkedListNode<Person> node, ItemContainerGenerator generator)
{
if (node != null)
{
TreeViewItem item = (TreeViewItem)generator.ContainerFromItem(node.Value);
if (node.Value == this.toSelectPerson)
{
item.IsSelected = true;
return;
}
item.ItemContainerGenerator.StatusChanged += delegate
{
if (item.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
ExpandAndSelect(node.Next, item.ItemContainerGenerator);
}
};
item.IsExpanded = true;
}
}
}
public class Person
{
public Person()
{
this.Children = new ObservableCollection<Person>();
this.Children.CollectionChanged += Children_CollectionChanged;
}
public string Name { get; set; }
public Person Parent { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
private void Children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
foreach (Person child in e.NewItems)
child.Parent = this;
}
}
}
<Window
x:Class="ForumProjects.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ForumProjects"
x:Name="Window" Title="MainWindow" Height="800" Width="600">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Person}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView x:Name="PersonList" ItemsSource="{Binding ElementName=Window, Path=Persons}"
Loaded="TreeView_Loaded"/>
</Window>
Best Regards,
Wei Zhou
Monday, February 4, 2008 8:15 AM
All replies
-
This is because the TreeViewItem is not intialized, so we are unable to get its container. The following example shows how to do this. I hope this helps.
Code Snippetnamespace ForumProjects
{
public partial class MainWindow : Window
{
public MainWindow()
{
this.Persons = new List<Person>()
{
new Person(){Name="A1"},
new Person(){Name="A2"},
};
this.Persons[0].Children.Add(new Person() { Name = "B1" });
this.Persons[0].Children.Add(new Person() { Name = "B2" });
this.Persons[1].Children.Add(new Person() { Name = "B3" });
this.Persons[1].Children.Add(new Person() { Name = "B4" });
this.Persons[0].Children[0].Children.Add(new Person() { Name = "C1" });
this.Persons[0].Children[0].Children.Add(new Person() { Name = "C2" });
this.Persons[0].Children[1].Children.Add(new Person() { Name = "C3" });
this.Persons[0].Children[1].Children.Add(new Person() { Name = "C4" });
this.Persons[1].Children[0].Children.Add(new Person() { Name = "C5" });
this.Persons[1].Children[0].Children.Add(new Person() { Name = "C6" });
this.Persons[1].Children[1].Children.Add(new Person() { Name = "C7" });
this.Persons[1].Children[1].Children.Add(new Person() { Name = "C8" });
this.toSelectPerson = this.Persons[1].Children[0].Children[1];
InitializeComponent();
}
public List<Person> Persons { get; private set; }
private Person toSelectPerson;
private LinkedList<Person> linkedPersons;
private void TreeView_Loaded(object sender, RoutedEventArgs e)
{
this.linkedPersons = new LinkedList<Person>();
this.linkedPersons.AddFirst(this.toSelectPerson);
FillLinkedPersons(this.toSelectPerson.Parent);
ExpandAndSelect(this.linkedPersons.First, this.PersonList.ItemContainerGenerator);
}
private void FillLinkedPersons(Person person)
{
if (person != null)
{
this.linkedPersons.AddBefore(this.linkedPersons.First, person);
FillLinkedPersons(person.Parent);
}
}
private void ExpandAndSelect(LinkedListNode<Person> node, ItemContainerGenerator generator)
{
if (node != null)
{
TreeViewItem item = (TreeViewItem)generator.ContainerFromItem(node.Value);
if (node.Value == this.toSelectPerson)
{
item.IsSelected = true;
return;
}
item.ItemContainerGenerator.StatusChanged += delegate
{
if (item.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
ExpandAndSelect(node.Next, item.ItemContainerGenerator);
}
};
item.IsExpanded = true;
}
}
}
public class Person
{
public Person()
{
this.Children = new ObservableCollection<Person>();
this.Children.CollectionChanged += Children_CollectionChanged;
}
public string Name { get; set; }
public Person Parent { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
private void Children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
foreach (Person child in e.NewItems)
child.Parent = this;
}
}
}
<Window
x:Class="ForumProjects.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ForumProjects"
x:Name="Window" Title="MainWindow" Height="800" Width="600">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Person}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView x:Name="PersonList" ItemsSource="{Binding ElementName=Window, Path=Persons}"
Loaded="TreeView_Loaded"/>
</Window>
Best Regards,
Wei Zhou
Monday, February 4, 2008 8:15 AM -
Hi Wei,
Sorry for a late response to this post. Your solution solved the issue. I could try this out today only. I had to slightly modify the code for my need but the results have come out really good.
Many thanks
Siva
Thursday, February 14, 2008 8:26 PM