views:

56

answers:

1

I have a ListBox that I bind to an ItemsSource, like this:

var foos = new ObservableCollection<Foo> { foo1, foo2, foo3 };
var listBox = new ListBox { ItemsSource = _foos };

Now I want to do some operations right away on the ListBoxItems that holds the items, but they don't seem to be created right away. Are they? Is there some event I can listen to in order to be notified, or am I simply trying to fetch the ListBoxItem's in an invalid way? I am doing it like this (and have verified that it works somewhere I know the ListBox is "ready"):

var lbi = listBox.ItemContainerGenerator.ContainerFromItem(foo1) as ListBoxItem;

Note that this is being done in a unit test, so I guess the ListBox is never rendered. Is that why the ListBoxItems aren't created? And can I manually trigger the creation of the ListBoxItems somehow?

+2  A: 

Items-creation is done async and depending on the panel, it can happen that it is not created at all (virtualization). The event your're looking for is ItemContainerGenerator.StatusChanged. Do a google-search for it on SO, you will find many examples. However directly searching and working with the items can get complex.

Here is a very good article that discusses the item-creation in detail. Look also for the ancestor-article .

BTW: I recommend you to look at the MVVM-pattern. While there is a small bit of time you loose learning it (not comparable to the time learnding WPF), it will save you a lot of time. Here you find a link to a video from Jason Dolinger that gives you a great start-point.

Update:

As promised in the comment, here a function to search the visual tree (only usable when virtualization is off).

void FindChildFrameworkElementsOfType<T>(DependencyObject parent,IList<T> list) where T: FrameworkElement{             
    DependencyObject child; 
    for(int i=0;i< VisualTreeHelper.GetChildrenCount(parent);i++){             
        child = VisualTreeHelper.GetChild(parent, i); 
        if (child is T) { 
            list.Add((T)child); 
        } 
        FindChildFrameworkElementsOfType<T>(child,list); 
    } 
} 
HCL
Thx. Will look into the articles and try using the StatusChanged event. I am already using MVVM, and the video is indeed great. However, in this case I need to get down to the details for the unit tests of a custom control inheriting ListBox that I'm working on.
stiank81
@stiank81: If your lists have few items, you can disable virtualizing with VirtualizingStackPanel.IsVirtualizing="False" on the ListBox. For small sets of data this would not be a problem. Depending on your unit test, you can disable the virtualization also only for the unit test.
HCL
Yes, I wanted to do this only for the unit tests, but it doesn't seem like I can reach it from the code. It says that it is a private Property, but why can I reach it from xaml then? Any idea if I can trigger this from code somehow?
stiank81
The article was really interesting! Thx! That explains alot, but still leaves me with problems.. Tried using the ItemContainerGenerator.StatusChanged event and waiting for it to execute before I continue, but it is never triggered in my unit tests. Any way I can trigger the generation manually?..
stiank81
@stiank81: Try yourListBox.SetValue(VirtualizingStackPanel.IsVirtualizing,false) or VirtualizingStackPanel.SetIsVirtualizing(yourListBox,false)
HCL
The second option works for deaktivating virtualization, but still no ListBoxItems, and still no StatusChanged triggered.. +1 btw..
stiank81
Another possibility to get the Items is through the VisualTreeHelper. If virtualization is off, all items should be available and you can get them through it. I will extend my answer...
HCL
@stiank81: I have never done a unit test for WPF. Are you shure that all the rendering-stuff and item-creation is done within your test?
HCL
Well - it seems like it's not happening.. I am creating the WPF object in the STA thread, but that's all really. So I guess it's not being rendered, and that's why the containers are never created? Do you know if there is anything I can do to trigger the rendering or something like that?..
stiank81
You can try to use RenderTargetBitmap to create an Image from your Visual, maybe this will trigger the creation. http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.rendertargetbitmap.aspx
HCL