tags:

views:

945

answers:

4

Is there a way to get at the ItemContaner of a selected item in a listbox? In Silverlight 2.0 Beta 1 I could, but the container is hidden in Beta 2 of Silverlight 2.0.

I'm trying to resize the listbox item when it is unselected to a specific size and when selected to a variable size. I also want to get the relative position of the selected item for animations. Growing to a variable size and getting the relative pasition is why i need to get to the listbox item.

I should clarify i'm not adding items to the listbox explicitly. I am using data binding in xaml and DataTemplates. What I have trouble accessing is the ItemContainer of the selected item's DataTemplate.

A: 

You could do it using reflection, but if they are hidden its probably because altering it directly may cause the listbox state to get out of whack. While MS controls are boring, they are very reliable. Messing about with their protected and private members may make them unstable, which isn't a good idea.

If you describe what you're doing, there may be a better way of going about it...

Will
A: 

If you are adding non-UI elements to the listbox (such as strings or non-UI data objects), then this is probably pretty difficult. However if you wrap your items in some sort of FrameworkElement-derived object before adding them to the listbox, you can use TransformToVisual to get the relative size and use Height and Width to set the size of the item.

In general you can wrap your objects in a ContentControl like the following. Instead of:

_ListBox.Items.Add(obj0);
_ListBox.Items.Add(obj1);

Do this:

_ListBox.Items.Add(new ContentControl { Content = obj0 });
_ListBox.Items.Add(new ContentControl { Content = obj1 });

Now when you get _ListBox.SelectedItem you can cast it to ContentControl and set the size and get the relative position. If you need the original object, simply get the value of the item's Content property.

dcstraw
+2  A: 

There is a way to obtain the Panel containing the item's UIElement and the mapping of items to UIElements. You have to inherit from ListBox (this actually works for any ItemsControl) and override PrepareContainerForItemOverride:

protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item);
        var el = element as FrameworkElement;
        if (el != null)
        {
            // here is the elements's panel:
            _itemsHost = el.Parent as Panel;

            // item is original item inserted in Items or ItemsSource
            // we can save the mapping between items and FrameworElements:
            _elementMapping[item] = el;
        }
    }

This is kind of hackish, but it works just fine.

MaxM
A: 

It appears that you can use relative binding to get at the Item Container from the ItemTemplate.

<TextBlock YourTargetProperty="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBoxItem}}, Mode=OneWay, Path=YourSourceProperty}" />

I found this solution here.

jpierson