How to Bind to the Index of a Collection in WPF

17 באפריל 2010

תגיות: , ,
3 תגובות

Let's say you have a customer class and you are binding a DataGrid to a collection of customers.

You would like the index of the customer in the collection to appear in the first column, like so:


One way to do this might be to add an Index property to the Customer class and bind to that.

I prefer not to go that way because it would pollute our business layer with presentation layer constraints.


Here is a different approach using a MultiBinding.

You can download the source code for this example from here.

This is our DataAccess Layer:

    public class Customer


        public string Name { get; set; }

        public int Age { get; set; }



    public class DataAccess


        static private List<Customer> customers;

        static public List<Customer> Customers




                if (customers == null)


                    customers = new List<Customer>


                        new Customer { Name="Bill", Age=40},

                        new Customer { Name="Alice", Age=35},

                        new Customer { Name="Fred", Age=30},

                        new Customer { Name="Tom", Age=20}



                return customers;




and here is the XAML:

<DataGrid Name="dg"




        <local:IndexConverter x:Key="indexConverter" />



        <DataGridTextColumn Header="Index">


                <MultiBinding Converter="{StaticResource indexConverter}">

                    <Binding />

                    <Binding RelativeSource=

                                "{RelativeSource AncestorType={x:Type DataGrid}}"





        <DataGridTextColumn Header="Name"

                           Binding="{Binding Name}"></DataGridTextColumn>

        <DataGridTextColumn Header="Age"

                           Binding="{Binding Age}"></DataGridTextColumn>



Here is the IndexConverter:

    class IndexConverter : IMultiValueConverter


        public object Convert(

            object[] values, Type targetType,

            object parameter, System.Globalization.CultureInfo culture)


            var customer = values[0] as Customer;

            var customers = values[1] as List<Customer>;

            return customers.FindIndex(c => c == customer).ToString();



        public object[] ConvertBack(

            object value, Type[] targetTypes,

            object parameter, System.Globalization.CultureInfo culture)


            throw new NotImplementedException();



and finally, the binding operation in the Loaded event:

        void MainWindow_Loaded(object sender, RoutedEventArgs e)


            dg.ItemsSource = DataAccess.Customers;


הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

3 תגובות

  1. Tamir Khason17 באפריל 2010 ב 22:21

    Well, if you really want to show the index of the item in view, do it within your view

    public class Conv : IValueConverter {

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
    var item = (ListViewItem)value;
    var view = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
    int index = view.ItemContainerGenerator.IndexFromContainer(item);
    return index;

  2. David Sackstein24 באפריל 2010 ב 21:25

    Hi Tamir,
    Thanks for the comment.
    But, wouldnt you agree that your solution ties the implementation tightly with the view (ListViewItem for instance).
    If I changed the view I would have to change the converter.

  3. Michael19 בפברואר 2011 ב 4:32

    I have tried Tamir Khason's approach, but

    always set the column-width to 0.

    Is it possible to make the column automatically fit to the width (like it does with _Binding Path=FirstName_), when using Binding Converter and RelativeSource?