Unable to find container from item in Treeview - silverlight

I got an ItemsControl (a Treeview or a TreevieItem) wich Item is filled with my own Model.
I wan't to programatically unfold the TreeView. So I try this:
var model = itemsControl_.Items.Select(i => i as MyModel).Where(ftn => ftn != null && ftn.key = searchedKey));
now that i have founded the model a want to unfold. I search for the container to unfold it:
var tvi = itemsControl_.ItemContainerGenerator.ContainerFromItem(model) as TreeViewItem;
if(tvi!=null)
{
if (!tvi.IsExpanded)
{
tvi.IsExpanded = true;
}
}
And sometimes tvi is null !?!
Can someone explain me how that can be possible ?

Based on your description, it seems you want to expand TreeViewItem.
I think this is most likely caused by the Virtualizating. The Virtualizating Attached Property is on by default for TreeView, which means if an item is not in the viewport, it probably didn't get an container.
If you call GetContainerFromItem on a TreeView, the ItemContainerGenerator searches only the direct child objects of the TreeView. So you need to recursively traverse the TreeView and child TreeViewItem objects. A further complication is that if the TreeView virtualizes its items (you enable virtualization by setting the VirtualizingStackPanel.IsVirtualizing property to true), the child items need to be created before you can check its data object.
Hope this will help.
Pls refer to http://blogs.msdn.com/b/wpfsdk/archive/2010/02/23/finding-an-object-treeviewitem.aspx
Regards
Dipak

Related

How to select first list box item by default?

I'm using ObservableCollection to bind data into list box. Is there a way to make first list item to be selected right after data binding? Is there any event I can use ?
Thank you
Right after (or any point after) setting the datacontext for the listbox (or parent object - probably the page), just set the selected index to the first item in the list.
listbox.SelectedIndex = 0;
If you've got a handler for when the selected index is changed then be sure to ignore when you first set the index.
Create a property named IsSelected in the object contained within the ObservableCollection. Bind this to the ListBoxItem's IsSelected property via a TwoWay binding.
Then, in the page's OnLoaded callback (or wherever you're binding the collection to the ListBox), do something like this
foreach( var obj in myCollection ) {
obj.IsSelected = false;
}
if( myCollection.Count > 0 ) {
myCollection[0].IsSelected = true;
}
// bind the collection to the listbox
why won't you try something like
var listBoxItem = ItemContainerGenerator.ContainerFromItem(myList.First());
listBoxItem.Focus();
or
listBoxItem.IsSelected = true;

Expand Root in TreeView when ItemSource changed

I have a ChildWindow in a Silverlight 4 App with a TreeView. The ItemSource is binded to an ObservableCollection of Items in a ViewModel. When the window opens the item are loaded from a webservice.
I have only one root node and I need it to be initially expanded. The TreeView even has the extension ExpandToDepth() which seems perfect but I don't know where I can call it. I didn't find an event that occurs after the items are updated from the ItemSource.
I tried using ItemContainerGenerator.ItemChanged and OnItemsChanged in TreeView but they are both executed before the tree view items are generated so the expand commands won't work.
How can I get this to work?
Try to register for your ObservableCollection's CollectionChange Event and do your actions there.
Derive from TreeView and create IsRootItemExpanded property and create same name property in ViewModel. In set accesser check if value true then call your method like this ExpandToDepth(1) When itemssource is need to update then set IsRootItemExpanded property true. You must to bind IsRootItemExpanded of TreeView to IsRootItemExpanded of ViewModel.
I solved my problem by overriding the PrepareContainerForItemOverride method in TreeView. I wondered why this is just called for the root node but it works.
public class ExpandedRootTreeView : TreeView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
TreeViewItem treeViewItem = element as TreeViewItem;
if (treeViewItem != null) treeViewItem.IsExpanded = true;
base.PrepareContainerForItemOverride(element, item);
}
}
Thanks to everybody who responded.

WPF - How to finding the tab a control is on

I'm very new to WPF and don't know how to do this. I have a text box in a tab item on a tab control. How can I programmatically (C#) determine what tab item is the parent of this text box? I would also like to determine what tab control is the parent of the tab item.
Thanks very much.
TabItem.Parent will provide the logical parent element of the TabItem; which will be the associated TabControl. You can use the same approach for any control with the TabItem.
((FrameworkElement)myTextBox.Parent).Parent;
If the item is deeper in the tree and becomes unknown in its depth you will need to begin to approach it in a recursive manner.
You can use FrameworkElement.Parent to walk up the hierarchy of a control in WPF. This should let you (recursively) walk up until you find the TabItem, then walk up to the TabControl from there.
I am newbie in WPF too, but what about cycle searching?
For example:
TextBox TB = new TextBox();
TabControl MyTabControl = new TabControl();
// ...
foreach (TabItem ti in MyTabControl.Items)
if (TB.Parent == ti)
{
// textbox is here!
MessageBox.Show(ti.ToString());
break;
}
Here is a generic method for finding parent controls: How can I find WPF controls by name or type?
You can call it like this:
TabItem owner = UIHelper.FindVisualParent<TabItem>(myTextBox);

C# WPF - Adding a child node to a selected node in treeview

In WPF treeview control, I need to add a child node to a parent node i select using mousedoubleclick event.
http://msdn.microsoft.com/en-us/library/system.windows.controls.treeview.selecteditem.aspx
I followed the step in the MSDN, but i get invalidCastException when i do this.
TreeViewItem newChild =
(TreeViewItem)treeView1.SelectedItem;
How can i solve this?
Thanks
SelectedItem returns the selected data item, not the visual representing it.
If you need to access the selected TreeViewItem, use the ItemContainerGenerator :
TreeViewItem item = treeView1.ItemContainerGenerator.ContainerFromItem(treeView1.SelectedItem) as TreeViewItem;
Not sure it works for nested items though... you might have to use the ItemContainerGenerator of the parent TreeViewItem, which wouldn't be very convenient
EDIT: just tested, indeed it only works for root nodes...
Anyway, the best way to add a node is to use bindings and HierarchicalDataTemplates. You just need to add the object to the data source, and the corresponding TreeViewItem will be added automatically (provided the containing collection implements INotifyCollectionChanged...)
What type of Items do you Add() to the Tree? The same type will be returned.
If it is mixed, use
TreeViewItem newChild = treeView1.SelectedItem as TreeViewItem;
if (newChild != null) { ... }

WPF ListBox - Getting UIElement instead of of SelectedItem

I created a ListBox that has a DataTemplate as Itemtemplate. However, is there an easy way to access the generated UIElement instead of the SelectedItem in codebehind?
When I access SelectedItem, I just get the selected object from my
ItemsSource collection. Is there a way to access the UIElement (ie. the
element generated from the DataTemplate together with the bound object)?
You are looking for the ItemContainerGenerator property. Each ItemsSource has an ItemContainerGenerator instance. This class has the following method that might interest you: ContainerFromItem(object instance).
Once you have a handle to the ListBoxItem, you can go ahead and browse the logical and visual tree. Check out Logical Tree Helper and Visual Tree Helper.
Like Andy said in the comments, just because the item exists in your collection doesn't mean a container has been generated for it. Any kind of virtualizing panel scenario will raise this issue; UIElements will be reused across the different items. Be careful with that as well.
siz, Andy and Bodeaker are absolutely right.
Here is how I was able to retrieve the textbox of the listbox's selected item using its handle.
var container = listboxSaveList.ItemContainerGenerator.ContainerFromItem(listboxSaveList.SelectedItem) as FrameworkElement;
if (container != null)
{
ContentPresenter queueListBoxItemCP = VisualTreeWalker.FindVisualChild<ContentPresenter>(container);
if (queueListBoxItemCP == null)
return;
DataTemplate dataTemplate = queueListBoxItemCP.ContentTemplate;
TextBox tbxTitle = (TextBox)dataTemplate.FindName("tbxTitle", queueListBoxItemCP);
tbxTitle.Focus();
}
(Note: Here, VisualTreeWalker is my own wrapper over VisualTreeHelper with various useful functions exposed)

Resources