views:

2276

answers:

2

I have a ListBox where the number of items is added based on and integer property set by a user. The items are created from a ControlTemplate resource that which is comprised of a Label and a TextBox inside of a DockPanel. The label is not data bound but I would like for it to have somewhat dynamic content based on the (index + 1) of the listboxitem for which it is contained. My question/problem is that I want to be able update the content of the label for each listbox item, but cannot access the label for some reason. I am unaware of any way to do this through data-binding of the label since the label is in a template and has no knowledge that it has a parent that is a listbox item. Can anyone help me clear up some of these confusions to get me back on the right track, please?

                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <DockPanel Background="Transparent" Height="28" Name="playerDockPanel" VerticalAlignment="Bottom">
                        <Label Name="playerNameLabel" DockPanel.Dock="Left" Content="Player"></Label>
                        <TextBox Height="23" Width ="150" Name="playerName" DockPanel.Dock="Right"/>
                    </DockPanel>
                </ControlTemplate>

I would like to be able to bind the content of the label in xaml, or update the content of the label in the code behind. I'm not sure what the best route would be.

A: 

UPDATE: Initially I was trying to find the label in the template like this....

  Label label = (Label)lbi.Template.FindName("playerNameLabel",lbi);

I found out that you have to call ApplyTemplate() in order to build the template's visual tree before it will be able to find the element.

BrandonS
A: 

You have to create a IMultiValueConverter that will get the index of your template:

public class PositionConverter : IMultiValueConverter
{
    public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
    {
        ItemsControl itemsControl = value[0] as ItemsControl;
        UIElement templateRoot = value[1] as UIElement;
        if (templateRoot != null)
        {
            UIElement container = ItemsControl.ContainerFromElement(itemsControl, templateRoot) as UIElement;
            if (container != null)
            {
                return itemsControl.ItemContainerGenerator.IndexFromContainer(container);
            }
        }

        return null;
    }

    public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

You should then use the converter into your DataTemplate:

<DataTemplate x:Key="itemTemplate">
    <DockPanel Background="Transparent" Height="28" Name="playerDockPanel" VerticalAlignment="Bottom">
        <Label Name="playerNameLabel" DockPanel.Dock="Left" Content="{Binding Title}"></Label>
        <Label Height="23" Width ="150" Name="playerName" DockPanel.Dock="Right">
            <Label.Content>
                <MultiBinding Converter="{StaticResource positionConverter}">
                    <!-- The ItemsControl-->
                    <Binding ElementName="listBox" />
                    <!-- The root UIElement-->
                    <Binding ElementName="playerDockPanel"/>
                </MultiBinding>
            </Label.Content>                    
        </Label>
    </DockPanel>
</DataTemplate>
sacha