How can I bind Wpf DataGridColumn to an object?

I want to bind the columns of my WPF DataGrid to some objects in a Dictionary like this:

Binding Path=Objects[i]

where Objects is my Dictionary of objects, so that each cell will represent an Object element. How can I do that?

I suppose that I need to create a template for my cell, which I did, but how to get the result of column binding in my template? I know that by default the content of a DataGridCell is a TextBlock and it’s Text property is set through column binding result, but if that result is an object I guess that I have to create a ContentTemplate. How do I do that, as the stuff I tried is not displaying anything.

Here it is what I tried:

<Style x:Key="CellStyle" TargetType="{x:Type dg:DataGridCell}">
    <Setter Property="Template"> ---it should realy be ContentTemplate?
      <Setter.Value>
        <ControlTemplate>
          <controls:DataGridCellControl CurrentObject="{Binding }"/> -- I would expect to get the object like this for this column path : Path=Objects[i] but is not working
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

So, to make myself completly clear, i want to get in CurrentObject property of my DataGridCellControl the current object that should result if I set the column binding in my data grid like this Path=Objects[i].

Thank you for any suggestion,

John.

Try this:

<ListView x:Name="listViewUsers" SelectionMode="Single" 
                              ItemsSource="{Binding ElementName=window1, Path=Users, Mode=TwoWay}" MouseDoubleClick="listViewUsers_MouseDoubleClick">
                        <ListView.View>
                            <GridView x:Name="gridViewUsers" AllowsColumnReorder="False">
                                <GridViewColumn>
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <Image Source="{Binding Path=IsAdministrator, Converter={StaticResource boolToImage}, ConverterParameter="Images/admin18.gif|Images/user18.gif"}" />
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>
                                <GridViewColumn Header="User Name" DisplayMemberBinding="{Binding Path=UserName}" Width="140" />
                                <GridViewColumn Header="Full Name" DisplayMemberBinding="{Binding Path=FullName}" Width="140" />
                                <GridViewColumn Header="Phone Number" DisplayMemberBinding="{Binding Path=PhoneNumber}" Width="110" />
                                <GridViewColumn Header="Access Type" DisplayMemberBinding="{Binding Path=AccessType}" Width="110">
                                </GridViewColumn>
                                <GridViewColumn>
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <Image Cursor="Hand" ToolTip="Delete User" Stretch="None" Source="Images/trash12.gif" MouseUp="DeleteUser" />
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>
                            </GridView>
                        </ListView.View>
                    </ListView>

Where in ItemsSource=”{Binding ElementName=window1, Path=Users, Mode=TwoWay}”

  • ElementName is the name of the Window in XAML (just add x:Name=”window1″ to the Window tag as with any other ontrol.

  • Users is a List, should work the same with Dictionary

  • Mode=TwoWay means that if the grid gets modified, the list will get modified too, and vice versa (Two way binding)

EDIT:

Try this:

XAML:

<ListView x:Name="listViewTest" ItemsSource="{Binding}">
<ListView.View>
    <GridView x:Name="gridViewTest">

    </GridView>
</ListView.View>
</ListView>

C#:

public class TheClass
    {
        public int Col1, Col2, Col3; 
        public Dictionary<int, OtherColumns> otherColumns = new Dictionary<int,OtherColumns>();
    }

    public class OtherColumns
    {
        public string ColumnName;
        public int Value;
    }

And call this method under Window_Loaded:

private void PopulateListView()
        {
            TheClass c = new TheClass();

            c.Col1 = 10;
            c.Col2 = 20;
            c.Col3 = 30;


            c.otherColumns.Add(0, new OtherColumns() { ColumnName = "Col4", Value = 40 });
            c.otherColumns.Add(1, new OtherColumns() { ColumnName = "Col5", Value = 50 });
            c.otherColumns.Add(3, new OtherColumns() { ColumnName = "Col6", Value = 60 });

            DataTable table = new DataTable();

// adding regular columns
            table.Columns.Add("Col1", typeof(int));
            table.Columns.Add("Col2", typeof(int));
            table.Columns.Add("Col3", typeof(int));

// adding dynamic columns
            foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns)
            {
                table.Columns.Add(pair.Value.ColumnName, typeof(int));
            }

            DataRow row = table.NewRow();

// adding regular column values to the DataTable
            row["Col1"] = c.Col1;
            row["Col2"] = c.Col2;
            row["Col3"] = c.Col3;

// adding dynamic column values to the DataTable
            foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns)
            {
                row[pair.Value.ColumnName] = pair.Value.Value;
            }

            table.Rows.Add(row);

            // Start binding the table.
            gridViewTest.Columns.Clear();

            System.Windows.Controls.GridViewColumn gvc;
            Binding binding;

            foreach (DataColumn column in table.Columns)
            {
                gvc = new System.Windows.Controls.GridViewColumn();
                binding = new System.Windows.Data.Binding();
                binding.Path = new PropertyPath(column.ColumnName);
                binding.Mode = BindingMode.OneWay;
                gvc.Header = column.Caption;
                gvc.DisplayMemberBinding = binding;
                gridViewTest.Columns.Add(gvc);
            }

            listViewTest.DataContext = table;
        }

I’m not saying it’s the best solution, but it could help. Let me know.

I made some helper classes so I could use the DataGrid as a kind of DataTable. In other words, I wanted the formatting, sorting, and polished look of the DataGrid without having to pre-fab some classes beforehand. The main reason I wanted this was for a testing suite, I wanted to be able to create an arbitrary number of columns and at runtime. Here’s what I got

public class DataRow
{
    internal List<object> Items = new List<object>();

    public object this[string value]
    {
        get { return Items[Convert.ToInt32(value)]; }
    }

    public string GetString(int index)
    {
        return Items[index].ToString();
    }

    public object GetObject(int index)
    {
        return Items[index];
    }

    public DataRow(params object[] values)
    {
        if (values == null || values.Length < 1)
            throw new Exception("You must pass in some values");

        Items.AddRange(values);            
    }
}  

public class GridConstructor
{
    public List<DataRow> Rows = new List<DataRow>();
    private DataRow headers;

    public GridConstructor(DataRow head)
    {
        headers = head;
    }

    public void BuildInto(DataGrid grid)
    {
        grid.AutoGenerateColumns = false;
        grid.Columns.Clear();
        int totalCols = 0;

        Type headType = headers.GetType();

        for (int i = 0; i < headers.Items.Count; i++)
        {
            grid.Columns.Add(GetCol(headers.GetString(i), String.Concat("[", i.ToString(),"]")));
            totalCols++;
        }                     

        int finalWidth = totalCols * (int)grid.ColumnWidth.Value + 15;
        grid.Width = finalWidth;

        grid.ItemsSource = Rows;
    }

    private DataGridTextColumn GetCol(string header, string binding)
    {
        DataGridTextColumn col = new DataGridTextColumn();
        col.IsReadOnly = true;            
        col.Header = header;
        col.Binding = new Binding(binding);

        return col;
    }

    public DataGrid Create(int colSize)
    {
        DataGrid grid = new DataGrid();
        grid.ColumnWidth = colSize;
        grid.CanUserAddRows = false;
        grid.AlternationCount = 2;
        BuildInto(grid);
        return grid;
    }
}

Putting this together, this is a sample use:

void SimpleTest_Loaded(object sender, RoutedEventArgs e)
    {            
        DataRow headers = new DataRow("Level", "Weapon Type", "vs None", "vs Leather", "vs Studded", "vs Brigandine");            
        GridConstructor gridConstructor = new GridConstructor(headers);            

        var weaponType = "Slash";
        for (int level = 1; level < 10; level++)
        {
            int damage = DiceCup.RollMulti(8, level);
            int damCloth = damage - DiceCup.RollMulti(2, level);
            int damLeather = damage - DiceCup.RollMulti(3, level);
            int damStudded = damage - DiceCup.RollMulti(4, level);
            int damBrigandine = damage - DiceCup.RollMulti(5, level);

            DataRow row = new DataRow(level, weaponType, damage, damCloth, damLeather, damStudded, damBrigandine);
            gridConstructor.Rows.Add(row);                
        }

        //Create the grid.
        var grid = gridConstructor.Create(100);


        //Create a chart.
        Chart chart = new Chart();
        chart.Height = 200;
        chart.LegendTitle = "Legend";
        chart.Title = "Slash vs Armor Types";                       
        chart.DataContext = gridConstructor.Rows;            


        //Create our series, or lines.
        LineSeries slashVsNone = new LineSeries();
        slashVsNone.Title = "vs None";
        slashVsNone.DependentValueBinding = new Binding("[2]");
        slashVsNone.IndependentValueBinding = new Binding("[0]");
        slashVsNone.ItemsSource = gridConstructor.Rows;            
        chart.Series.Add(slashVsNone);

        //Presentation is a stackpanel on the page.            
        presentation.Children.Add(grid);
        presentation.Children.Add(chart);             
    }

And the output:

alt text http://quiteabnormal.com/images/codeSample.jpg

Please note that the grid coloring is from universal styles set on the page. If you use the GridConstructor.BuildInto() method you can specify a grid you’ve pre-formatted yourself in Blend or somesuch.

Just one thing, the GridConstructor makes some assumptions about the column’s initial settings. You can change the class to make it more customizable if you like, but this is what I needed so I wanted to be able to make it without fuss.

Leave a Comment