Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: Binding lists in XAML- how can an item know its position in the list?

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?

like image 365
user256890 Avatar asked Aug 31 '10 08:08

user256890


1 Answers

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...

like image 112
Eugene Cheverda Avatar answered Oct 05 '22 23:10

Eugene Cheverda