views:

24

answers:

3

Given the following XAML code that with a ListControl like behavior:

    <StackPanel>
        <ItemsControl Name="_listbox" ItemsSource="{Binding ElementName=_userControl, Path=DataContext}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <DockPanel>
                         ...
                    </DockPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>

Since the list can be long (100-200 items), and the items look similar, I think it would helpful for the user during scrolling if every item would display their position in the list. How could an item in the template know its own position in the list?

A: 

According to MSDN Magazine article "Charting with DataTemplates":

[...]the DataTemplate would need access to the index of the particular data item in the collection. But it's easy enough to include this information in the business object[...]

So, unless there was a change in .NET 4, there is no "index of this item" property unless it is explicitly included in the model.

Richard
A: 

Here is a hack solution. We can use Value Conversion with DataBinding. So the first step is to declare our ValueConvertor:

public class ListItemToPositionConverter : IValueConverter
    {
        #region Implementation of IValueConverter

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var item = value as ListBoxItem;
            if (item != null)
            {
                var lb = FindAncestor<ListBox>(item);
                if (lb != null)
                {
                    var index = lb.Items.IndexOf(item.Content);
                    return index;
                }
            }
            return null;
        }            

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

        #endregion
    }

Declare wherever you want this static method in order to obtain ListBox parent:

public static T FindAncestor<T>(DependencyObject from) where T : class
        {
            if (from == null)
                return null;

            var candidate = from as T;
            return candidate ?? FindAncestor<T>(VisualTreeHelper.GetParent(from));
        }

Then in ListBox.Resources declare our convertor as follows:

<ListBox.Resources>
                <YourNamespace:ListItemToPositionConverter x:Key="listItemToPositionConverter"/>
            </ListBox.Resources>

And finally - DataTemplate:

<ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Converter={StaticResource listItemToPositionConverter}}"/>
                        <Label Content="{Binding Path=DisplayName}"></Label>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>

Note: in this example the items will be numerated starting with 0 (zero), you can change it in Convert method by adding 1 to result.

Hope this helps...

Eugene Cheverda
A: 

This sample supports sorting:

Numbered listbox

Wallstreet Programmer